Quickly disable external API calls in your FastAPI application using FastAPI and LaunchDarkly kill switch flags featured image

Kill switches are a type of feature flag that allows you to shut off features in your application quickly. They are useful for:

  • Emergency shutoffs of external APIs and services.
  • Responding to unexpected spam or traffic spikes.
  • Other operational incidents where you need to quickly put the brakes on without causing additional disruption.

In this tutorial you will learn to add a kill switch to disable 3rd-party API calls in a FastAPI application, using the LaunchDarkly Python SDK.

We’ll use the Dad Jokes API as a data source here since it’s free, doesn’t require authentication, and I needed to know why the chicken crossed the road. 🙈

What is FastAPI?

FastAPI is a new kid on the block in terms of Python frameworks. It offers many benefits such as:

Prerequisites

Set up a new Python project

Create a directory on your local machine called fastapi-demo. Navigate into that directory. Set up and activate a virtual environment. You can do so by typing the following commands into your terminal:

mkdir fastapi-demo
cd fastapi-demo
python -m venv venv
source venv/bin/activate

Create a requirements.txt file in your fastapi-demo directory. Add the following lines to specify the dependencies and versions you’ll need to run this project:

fastapi>=0.114.1
fastapi-cli>=0.0.5
requests>=2.3.2
launchdarkly-server-sdk>=9.7.1

Save the requirements.txt file. Run the following commands in your terminal to install the packages into your virtual environment:

pip install -r requirements.txt

Get started with FastAPI

In your fastapi-demo directory, create a new file named main.py. Add the following code:

from fastapi import FastAPI

app = FastAPI()

@app.get("/")
async def root():
    return {"message": "Hello World"}

Run the server by typing the following command in your terminal:

fastapi dev main.py

If you open http://127.0.0.1:8000/ in a browser, you should see a JSON response with a hello world message.
To see the auto-generated docs, you can visit http://127.0.0.1:8000/docs#/ .

Add an HTML page to a FastAPI application

Next, we’ll add another route that returns HTML instead of JSON and displays a random dad joke. In the main.py file, add the following new lines of code that are commented below:

from fastapi import FastAPI
# add the following new import statements
from fastapi.responses import HTMLResponse
import requests
app = FastAPI()

# add this new function to call the dad jokes API
def call_dad_joke_api():
   headers = {"Accept": "text/plain", "User-Agent": "LaunchDarkly FastAPI Tutorial"}
   response = requests.get(url='https://icanhazdadjoke.com/', headers=headers)
   return response.content.decode("utf-8")

@app.get("/")
async def root():
    return {"message": "Hello World"}

# Add this new route to return an HTML response with a joke
@app.get("/joke/", response_class=HTMLResponse)
async def get_joke():
   joke = call_dad_joke_api()
   html = """
   <html>
       <head>
           <title>My cool dad joke app</title>
       </head>
       <body>
           <h1>{joke}</h1>
       </body>
   </html>
   """.format(joke=joke)
   return html

Save the main.py file. FastAPI should automatically reload on the server side. Go to http://127.0.0.1:8000/joke/ in your browser. Your page should contain a joke. Feel free to groan out loud.

A webpage that says "Hey dad did you get a haircut? No I got them all cut."

Configure your LaunchDarkly kill switch flag

We're going to step away from the FastAPI app for a second, and set up our LaunchDarkly configuration. 

In the LaunchDarkly app, click on “Flags” in the left navigation menu and then click one of the “Create flag” buttons.

Screenshot demonstrating how to create a flag in the LaunchDarkly app.

Configure your flag as follows:

  • Name your flag “use-dadjokes-api”. When you type in the Name, the Key field will automatically populate.
  • Enter some text in the description field to explain the purpose of this flag. “When enabled, pull jokes from the dadjokes API. When disabled, pull from a local file.”
  • Select “Kill Switch” as the flag type.

Screenshot demonstrating how to configure a kill switch flag.

Click the “Create Flag” at the bottom of this dialog.

On the following screen, click the dropdown menu next to the “Production” environment. Copy the SDK key by selecting it from the dropdown menu, we’ll need it in a second.

Screenshot demonstrating how to copy the LaunchDarkly SDK key from the flag configuration screen.

Very important - turn the flag on using the toggle switch! Then click the “Review and save” button at the bottom.

screenshot demonstrating how to turn a kill switch flag on.

Add a comment and verify the name of the environment, then click the “Save changes” button.

Screenshot demonstrating "Save changes" confirmation dialog for enabling a kill switch flag.

Add the LaunchDarkly Python SDK to a FastAPI application

Now we’ll add the LaunchDarkly Python SDK to our FastAPI application. We’ll need to use FastAPI lifespan events to instantiate and shut down the connection to LaunchDarkly. 

Add a new file called .env to your fastapi-demo folder. Add the following line to it:

export LAUNCHDARKLY_SDK_KEY='INSERT YOUR SDK KEY HERE'

Paste in the SDK key you copied from LaunchDarkly. Save the .env file. This approach reduces the risk of accidentally committing your SDK key to source control and compromising your security. Run the following command in your terminal where the virtual environment is activated, to invoke the environment variable:

source .env

In your main.py file, add the following new lines of code that are commented below:

from fastapi import FastAPI
from fastapi.responses import HTMLResponse
import requests

# Add the following new import statements
from contextlib import asynccontextmanager
import ldclient
from ldclient import Context
from ldclient.config import Config
import os
import random

# Add this new function to instantiate and shut down the LaunchDarkly client
@asynccontextmanager
async def lifespan(app: FastAPI):
   # initialize the LaunchDarkly SDK
   ld_sdk_key = os.getenv("LAUNCHDARKLY_SDK_KEY")
   ldclient.set_config(Config(ld_sdk_key))
   yield
   # Shut down the connection to the LaunchDarkly client
   ldclient.get().close()

# Add this new parameter
app = FastAPI(lifespan=lifespan)

def call_dad_joke_api():
   headers = {"Accept": "text/plain", "User-Agent": "LaunchDarkly FastAPI Tutorial"}
   response = requests.get(url='https://icanhazdadjoke.com/', headers=headers)
   return response.content.decode("utf-8")

# Add this new function as a fallback when external API calls are disabled
def get_dad_joke_from_local():
   jokes = [
       "what's black and white and red all over? The newspaper.",
       "Why does Han Solo like gum? It's chewy!",
       "Why don't skeletons ride roller coasters? They don't have the stomach for it.",
       "Why are pirates called pirates? Because they arrr!",
       "I'm hungry! Hi Hungry, I'm Dad."
   ]
   return random.choice(jokes)

@app.get("/")
async def root():
    return {"message": "Hello World"}

@app.get("/joke/", response_class=HTMLResponse)
async def get_joke():
   # Replace the line where the joke variable is defined with the following lines
   context = Context.builder("context-key-123abc").name("Dad").build()
   use_dadjokes_api = ldclient.get().variation("use-dadjokes-api", context, False)
   if use_dadjokes_api:
       joke = call_dad_joke_api()
   else:
       joke = get_dad_joke_from_local()

   html = """
   <html>
       <head>
           <title>My cool dad joke app</title>
       </head>
       <body>
           <h1>{joke}</h1>
       </body>
   </html>
   """.format(joke=joke)
   return html

Restart the server if you turned it off to load our environment variables. Reload http://127.0.0.1:8000/joke/ in your browser and be “rewarded” with a joke that’s not in the local list in the get_dad_joke_from_local function.

Flip back to LaunchDarkly and disable your flag. Click “Review and save” again as you did previously when you enabled it.  You should see a random joke from the locally defined list instead of the API. 💥

Note: when building a production use case, you might want to start with your flag disabled rather than enabled as we did here. Adding that extra step will help you ensure everything works as intended before exposing a new feature.

Wrapping it up: Adding LaunchDarkly kill switches to a FastAPI app

In this post you’ve learned how to use the LaunchDarkly Python SDK to add kill switch flags to your FastAPI application and shut off external API calls. If you want to learn more about what you can do with Python and LaunchDarkly, you might be interested in:

Thanks for reading! If you have any questions, or just want to tell me your best/worst dad joke, you can reach me via email (tthurium@launchdarkly.com), X/Twitter, or LinkedIn.

Like what you read?
Get a demo
Related Content

More about De-risked releases

September 17, 2024