Introduction to FastAPI API Integration

Welcome to the fifth lesson of our course on building an image generation service with FastAPI! In our previous lessons, we've built several key components of our application: the PromptManager for formatting user inputs, the ImageManager for storing and processing images, the ImageGeneratorService for connecting to Google's Gemini API, and most recently, the ImageGeneratorRouter, which handles input validation and response formatting.

Now it's time to bring everything together by creating the FastAPI application that will expose our functionality through HTTP endpoints. This is the final piece of our backend architecture that will allow users to interact with our image generation service through a web interface.

In the previous lesson, we built the ImageGeneratorRouter, which acts as an intermediary between our service layer and the API routes we'll create today. The router handles the business logic of validating inputs, calling the appropriate service methods, and formatting responses. Now, we'll create the FastAPI routes that will receive HTTP requests from clients and pass them to our router.

Our FastAPI API will have three main routes:

  1. A route to serve the main HTML page
  2. A route to handle image generation requests
  3. A route to retrieve all previously generated images

By the end of this lesson, you'll have a complete FastAPI API that integrates with the router we built previously, providing a clean interface for clients to generate and retrieve images.

Setting Up the FastAPI Application

Let's start by creating our FastAPI application. We'll set up the basic structure in our app/main.py file:

In this code, we're importing the necessary components from FastAPI: the FastAPI class to create our application, the Request object to access incoming request data, and the HTTPException class to handle errors. We're also importing Jinja2Templates for serving HTML templates and StaticFiles for serving static files like CSS and JavaScript. Finally, we're importing our ImageGeneratorRouter class that we created in the previous lesson.

We create a FastAPI application instance by calling FastAPI() with a title for our API. This title will appear in the automatically generated API documentation.

We determine the base directory of the current script using os.path.dirname(os.path.abspath(__file__)). This allows us to set up paths relative to the script's location, which is useful for accessing templates and static files.

Next, we set up Jinja2Templates to handle our HTML templates. We specify the directory where our templates are located using os.path.join(BASE_DIR, "templates"), which is typically a folder named "templates" in the root of our project.

We also mount a static files directory to serve static assets like CSS, JavaScript, and images. This is done using the app.mount() method, which takes a URL path, a StaticFiles instance, and a name for the mount point. We use os.path.join(BASE_DIR, "static") to specify the directory for static files.

Finally, we create an instance of our ImageGeneratorRouter. This router will handle the business logic for our API endpoints. By creating it once at the application level, we ensure that all routes can access the same router instance, which helps maintain consistency across requests.

With these basic components in place, our FastAPI application is ready to have routes defined. The application will serve as the entry point for all client requests, routing them to the appropriate router methods based on the URL and HTTP method.

Defining API Routes

Now that we have our FastAPI application set up, let's define the routes that will handle client requests.

Index Route

We'll start with the index route, which will serve the main HTML page of our application:

The @app.get("/") decorator tells FastAPI that this function should be called when a client makes a GET request to the root URL of our application. The function takes a Request parameter, which is required by Jinja2Templates to render the template.

The function returns the result of templates.TemplateResponse(), which tells FastAPI to find the image_generator.html template in the templates directory and render it as the response. We pass a context dictionary containing the request object, which is required by Jinja2Templates.

Generate Image Route

Next, let's define the route for generating images:

This route is more complex than the index route. The decorator @app.post("/api/generate_image") specifies that this function should be called when a client sends a POST request to the /api/generate_image URL.

Inside the function, we extract the user_input from the request body using FastAPI's Body parameter. The ... indicates that this parameter is required, and embed=True means that the parameter will be embedded in a JSON object with the key user_input.

We then pass this input to our router's generate_image method, which will validate the input, call the service to generate an image, and format the response.

The router might return an error response as a tuple containing a dictionary with an 'error' key and a status code. We check for this pattern and raise an HTTPException with the appropriate status code and error message if an error is detected.

If there's no error, we simply return the response from the router, which should be a dictionary containing the base64-encoded image data.

Get Images Route

Finally, let's define the route for retrieving all previously generated images:

This route is defined with the decorator @app.get("/api/get_images"), which specifies that it should be called when a client sends a GET request to the /api/get_images URL.

The function simply calls our router's get_images method, which retrieves all stored images and formats them as a JSON response. This response is then passed back to the client.

With these three routes, our FastAPI API provides a complete interface for clients to interact with our image generation service. Clients can view the main page, generate new images, and retrieve previously generated ones.

Configuring the FastAPI Server

Now that we have our FastAPI application and routes defined, let's configure the server to run our application. We'll add the following code at the end of our app/main.py file:

This code block checks if the script is being run directly (as opposed to being imported as a module). If it is, it starts the Uvicorn server with specific configuration options.

FastAPI doesn't come with a built-in development server like Flask does. Instead, it relies on ASGI servers like Uvicorn to run the application. Uvicorn is a lightning-fast ASGI server that's perfect for running FastAPI applications.

The "main:app" parameter tells Uvicorn where to find the FastAPI application. In this case, it's looking for an object named app in a module named main.

The host="0.0.0.0" parameter tells Uvicorn to listen on all available network interfaces. This is important if you want to access your application from other devices on your network.

The port=8000 parameter tells Uvicorn to listen on port 8000 for incoming requests. You can choose any available port on your system, but 8000 is the default for FastAPI applications.

The reload=True parameter enables Uvicorn's auto-reload feature, which automatically restarts the server when you make changes to your code. This is very useful during development but should be disabled in a production environment for performance reasons.

When you run this script, you should see output similar to:

This indicates that your FastAPI server is running and ready to accept requests. You can access your application by opening a web browser and navigating to http://localhost:8000/ (or the appropriate IP address if accessing from another device).

One of the great features of FastAPI is that it automatically generates interactive API documentation. You can access this documentation by navigating to http://localhost:8000/docs in your web browser. This will show you all the available endpoints, their parameters, and allow you to test them directly from the browser.

Summary and Practice Preview

In this lesson, we've built a complete FastAPI API that integrates with our ImageGeneratorRouter to provide a web interface for our image generation service. Let's review what we've accomplished:

  1. We set up a FastAPI application with the necessary configuration, including template and static file handling.
  2. We created an index route to serve the main HTML page of our application.
  3. We implemented a POST endpoint for generating images, which extracts user input from the request body and passes it to our router.
  4. We set up a GET endpoint for retrieving all previously generated images.
  5. We configured the Uvicorn server to run our FastAPI application on a specific port and listen on all network interfaces, with auto-reload enabled for development.

Our FastAPI API now provides a complete interface for clients to interact with our image generation service. The API routes receive HTTP requests, extract the necessary data, and pass it to our router, which handles the business logic of validating inputs, calling the appropriate service methods, and formatting responses.

This completes the server-side portion of our image generation application. We've built a robust, modular architecture with a clear separation of concerns:

  • The PromptManager handles prompt formatting
  • The ImageManager manages image storage and processing
  • The ImageGeneratorService connects to the Gemini API and coordinates the other components
  • The ImageGeneratorRouter validates inputs and formats responses
  • The FastAPI API routes client requests to the appropriate router methods

In the upcoming practice exercises, you'll have the opportunity to test the API endpoints we've created. You'll send requests to generate images with different prompts and retrieve the stored images. You'll also explore how the API handles error cases, such as missing or invalid inputs.

By the end of these exercises, you'll have a solid understanding of how to build a complete web API with FastAPI, integrating it with a router-based architecture to provide a clean, consistent interface for clients. This knowledge will be valuable not just for image generation services but for any web application you build in the future.

Sign up
Join the 1M+ learners on CodeSignal
Be a part of our community of 1M+ users who develop and demonstrate their skills on CodeSignal