Back to Posts
Jun 23, 2021

FastAPI auto generated load testing with K6

Explore k6 load testing with FastAPI auto generated openapi spec.

FastAPI and k6

Overview

K6.io  is a load testing tool I’ve started using in some projects at work with very good results. Searching to speed up the test creation process while reading k6 blog and docs ended up discovering this post  and remembered FastAPI  generates the Openapi spec from routes.

Fastapi is a high-performance web framework for building APIs with Python. Amazing tool and community, just give it a try.

k6 was just acquired  by Grafana so expect larger adoption in the cloud native ecosystem.

What are we doing here?

  1. Launch a FastAPI sample app with a prebuilt docker image  form the author of the framework.

  2. Create a k6 script from the openapi spec generated by FastAPI

  3. Execute a k6 load test that came from another dimension and smell the magic.

Requirements

No packages requirements if you already have docker and docker-compose. Create these two files in your local directory (JFYI: I use linux and bash):

version: '3.8' services: fastapi: image: tiangolo/uvicorn-gunicorn-fastapi:python3.7 volumes: - ${PWD}/main.py:/app/main.py command: /start-reload.sh ports: - 80:80 openapi-cli: image: openapitools/openapi-generator-cli volumes: - ${PWD}:/ci command: generate -i http://fastapi/openapi.json -g k6 -o /ci/k6/ --skip-validate-spec k6: image: loadimpact/k6 volumes: - ${PWD}:/ci command: run /ci/k6/script.js
from typing import Optional from fastapi import FastAPI, Header, HTTPException from pydantic import BaseModel fake_secret_token = "coneofsilence" fake_db = { "foo": {"id": "foo", "title": "Foo", "description": "There goes my hero"}, "bar": {"id": "bar", "title": "Bar", "description": "The bartenders"}, } app = FastAPI() class Item(BaseModel): id: str title: str description: Optional[str] = None @app.get("/items/{item_id}", response_model=Item) async def read_main(item_id: str, x_token: str = Header(...)): if x_token != fake_secret_token: raise HTTPException(status_code=400, detail="Invalid X-Token header") if item_id not in fake_db: raise HTTPException(status_code=404, detail="Item not found") return fake_db[item_id] @app.post("/items/", response_model=Item) async def create_item(item: Item, x_token: str = Header(...)): if x_token != fake_secret_token: raise HTTPException(status_code=400, detail="Invalid X-Token header") if item.id in fake_db: raise HTTPException(status_code=400, detail="Item already exists") fake_db[item.id] = item return item

Start FastAPI app

docker-compose up fastapi

Launch the python app and check the auto-generated docs at http://localhost/docs 

Auto generate K6 script from Openapi spec

docker-compose run -u ${UID} --rm openapi-cli

The script need to be updated/tuned after being generated. Check again the recomendations  by k6 in the linked post. This is a slightly updated version of the script.

Copy this file to ${PWD}/ci/k6/script.js or check the required changes:

The fastapi app is running in reload mode if you need to change/test something.

import http from "k6/http"; import { group, check, sleep } from "k6"; import { randomString } from "https://jslib.k6.io/k6-utils/1.1.0/index.js"; const BASE_URL = "http://fastapi"; const SLEEP_DURATION = 0.1; let xToken = "coneofsilence"; let randomName = randomString(8); export default function() { group("/items/", () => { let url = BASE_URL + `/items/`; let body = {"id": `${randomName}`, "title": "string", "description": "string"}; let params = {headers: {"Content-Type": "application/json", "x-token": `${xToken}`, "Accept": "application/json"}}; console.log(JSON.stringify(body)); let request = http.post(url, JSON.stringify(body), params); check(request, { "Successful Response": (r) => r.status === 200 }); sleep(SLEEP_DURATION); }); group("/items/{item_id}", () => { let itemId = `${randomName}`; let url = BASE_URL + `/items/${itemId}`; let params = {headers: {"x-token": `${xToken}`, "Accept": "application/json"}}; let request = http.get(url, params); check(request, { "Successful Response": (r) => r.status === 200 }); sleep(SLEEP_DURATION); });

Execute K6 script

docker-compose run --rm k6

k6s-fastapi-run

docker-compose down

Related

© 2026 Sergio Teran
Privacy & cookiesGopher by Renée French (CC BY 4.0), modified