Inhaltsverzeichnis


Korbinian Habereder

FastAPIRobynAPIEntwicklung

03.06.2025

Framework-VergleichFastAPI vs. Robyn: Ein detaillierter Vergleich

In der Welt der modernen API-Entwicklung stehen Entwickler oft vor der Frage: Welches Framework ist das richtige für mein Projekt? FastAPI und Robyn sind zwei der (mehr oder weniger) aufstrebenden Stars in der Python-API-Entwicklung. Beide bieten moderne Features und hohe Performance, unterscheiden sich aber in einigen wichtigen Aspekten. In diesem Artikel werfen wir einen detaillierten Blick auf die Gemeinsamkeiten und Unterschiede dieser beiden Frameworks.

FastAPI vs. Robyn Vergleich

Einführung

Die Wahl des richtigen API-Frameworks ist entscheidend für den Erfolg eines Projekts. Während FastAPI bereits seit einigen Jahren etabliert ist, gewinnt Robyn als neuerer Player zunehmend an Popularität. Beide Frameworks versprechen hohe Performance und moderne Entwicklungsansätze, aber sie unterscheiden sich in ihrer Implementierung und ihren Stärken. In diesem Artikel werden wir die wichtigsten Aspekte beider Frameworks vergleichen und dir helfen, die richtige Wahl für dein Projekt zu treffen.

Gemeinsamkeiten

FastAPI und Robyn teilen einige grundlegende Eigenschaften, die sie zu modernen und effizienten API-Frameworks machen:

  • Beide sind moderne, asynchrone Web-Frameworks
  • Sie bieten eine hohe Performance durch asynchrone Verarbeitung
  • Beide unterstützen OpenAPI/Swagger-Dokumentation
  • Sie nutzen moderne Python-Features wie Type Hints
  • Beide sind leichtgewichtig und modular aufgebaut

Unterschiede

Runtime

FastAPI basiert auf Starlette und Uvicorn als ASGI-Server, während Robyn seine eigene Runtime in Rust implementiert hat. Dies führt zu interessanten Unterschieden: FastAPI profitiert von der reifen Python-Ökosystem-Integration und der breiten Community-Unterstützung, während Robyn durch seine Rust-Implementierung potenziell bessere Performance bei bestimmten Workloads bieten kann. Allerdings bedeutet die Rust-Implementierung auch, dass Robyn weniger flexibel bei der Integration von Python-Bibliotheken ist und möglicherweise mehr Wartungsaufwand erfordert.

Endpoint-Handhabung

Während beide Frameworks ähnliche Ziele verfolgen, unterscheiden sie sich in ihrer Implementierung von Endpoints:

FastAPI nutzt einen dekoratorbasierten Ansatz mit starkem Fokus auf Typisierung und Validierung, sowie request Destrukturierung und Injektion:

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()

class Item(BaseModel):
    id: str
    name: str
    price: float

@app.post("/items/")
async def create_item(item: Item):
    # create item in db
    # ...
    return item

@app.put("/items/{item_id}")
async def update_item(item_id: str, item: Item):
    """
    A client would call me like: PUT {base_url}/items/0485fd43-1345-4336-877c-4b47758102ea

    And `item_id` is automatically made available to this endpoint!
    """
    # update item in db
    # ...
    return item

@app.put("/items/{item_id}/move")
async def move_item(item_id: str, item: Item, directory: str | None = None):
    """
    A client would call me like: PUT {base_url}/items/0485fd43-1345-4336-877c-4b47758102ea/move?directory=new-n-shiny

    And `directory` is automatically made available to this endpoint!
    """
    # move item
    # ...
    return item

Robyn hingegen bietet einen etwas flexibleren, aber meiner Meinung nach umständlicheren, Ansatz der Injektion von Pfad- und Queryparametern:

# Why import types from three different modules?
from robyn import Robyn, Request
from robyn.types import PathParams
from robyn.robyn import QueryParams

app = Robyn(__file__)

@app.post("/items/")
async def create_item(request: Request):
    data = await request.json()
    return data

@app.put("/items/:item_id")
async def update_item(
    request: Request,
    path_parameters: PathParams,  # NOTE: variable name has to be `path_parameters` for injection to work
):
    item_id: str = str(path_parameters["item_id"])
    # update item in db
    # ...
    return item

@app.put("/items/:item_id")
async def move_item(
    request: Request,
    path_parameters: PathParams,
    query_parameters: QueryParams,  # NOTE: variable name has to be `query_parameters` for injection to work
):
    item_id: str = str(path_parameters["item_id"])
    directory: str = query_parameters.get("directory", None)
    # move item
    # ...
    return item

Übrigens sind alle Pfad- und Queryparameter auch im Request Model verfügbar. Man kann sich also die Injektion theoretisch sparen.

ORM-Unterstützung

Die Unterstützung von Datenbankoperationen ist ein wichtiger Aspekt bei der Framework-Auswahl:

FastAPI:

  • Ermöglicht einfache Integration mit ORMs wie SQLAlchemy - dank Pydantic
  • Unterstützt asynchrone ORMs wie Tortoise ORM
  • Verfügt über eine aktive Community mit zahlreichen Beispielen und Best Practices für ORM-Nutzung
  • Generiert automatisch OpenAPI-Dokumentation auf Basis der Datenbankmodelle
  • Bietet mit SQLModel eine eigene ORM-Option auf Basis von SQLAlchemy und Pydantic

Robyn:

  • Flexibler in der Wahl der Datenbank-Lösung (auch Rust ORMs!)
  • Weniger vordefinierte Patterns für Datenbankoperationen

Serialisierung und Validierung

Die Art und Weise, wie Daten validiert und serialisiert werden, unterscheidet sich deutlich:

FastAPI:

  • Nutzt Pydantic für Validierung und Serialisierung
  • Strikte Typisierung und Validierung
  • Automatische Generierung von OpenAPI-Schemas
  • Umfangreiche Validierungsmöglichkeiten (durch Pydantic)

Robyn:

  • Flexiblere Validierungsmöglichkeiten
  • Weniger strikte Typisierung
  • Manuelle Serialisierung/Deserialisierung (zum Beispiel über jsonify) Auch wenn dies nicht unbedingt notwendig ist. Die Dokumentation von Robyn ist hier nicht 100% eindeutig: Robyn jsonify Docs (jsonify wird zwar importiert aber nicht verwendet; Im Test musste man jsonify auch gar nicht importieren, ein Dict als Response reicht völlig aus)

FFIs

Zumindest wenn man CPython verwendet steht es einem schon immer frei gewisse Teile seines Python Codes in C / C++ umzusetzen (falls nicht schon passiert; stdlib, etc.) und damit zu beschleunigen. Da Robyn über eine Rust Runtime verfügt, ermöglicht dieses Framework allerdings eine Kinderleichte Integration von Rust Code!

Für unseren kleinen Performance-Vergleich lasse ich Fibonacci Zahlen bis zur (maximal) 30er Größe generieren. Hierbei werden keine Tricks wie Memoization verwendet, um die rohe Python Performance zu zeigen:

def py_fib(n: int):
    if n < 2:
        return n
    return py_fib(n - 1) + py_fib(n - 2)

Diesen "Generator" habe ich auch (krude, und ohne Rekursion) in Rust implementiert:

// rustimport:pyo3

//:
//: [dependencies]
//: num-bigint = "0.4"
//: num-traits = "0.2"

use pyo3::prelude::*;
use num_bigint::BigUint;
use num_traits::{Zero, One};

#[pyfunction]
fn fibonacci(term: u64) -> PyResult<String> {
    if term == 0 {
        return Ok("0".to_string());
    }
    
    let (mut a, mut b): (BigUint, BigUint) = (Zero::zero(), One::one());
    for i in 1..=term {
        let temp = b.clone();
        b = a + b;
        a = temp;
    }
    
    Ok(b.to_string())
}

Kinderleicht war das ganze, da ich mich nur um die Implementierung kümmern musste. Dependencies können über Kommentare definiert werden und werden automatisch von der Robyn CLI aufgelöst.

Nachdem man also seinen Rust Code geschrieben hat reicht folgender Befehl:

robyn --compile-rust-path "my-robyn-rust-dir"

Und schon wird wie durch Magie (PyO3) der Rust Code compiliert und in eine Plattformabhängige Library gepackt!

Diese kann dann wie ein normales Python Module importiert werden (meine Rust Datei heißt native_fib.rs und liegt im gleichen Verzeichnis wie die Robyn main.py):

from native_fib import fibonacci as rs_fibonnacci

Performance-Vergleich

Wie schon erwähnt wird zum Vergleich der Performance die Generierung von Fibonacci Zahlen sowie folgendes Setup benutzt:

  1. Ein Endpoint / welcher ein einfaches JSON zurück gibt:
    # fastapi implementation
    @app.get("/")
    async def root():
        return {"response": "success"}
    
    # robyn implementation
    @app.get("/")
    async def root(request: Request):
        return {"response": "success"}
    
  2. Eine locust Konfigurationsdatei mit einem Task:
    1. Ruft / auf mit 10, 1000 und 10.000 Usern
  3. Ein Endpoint /fibonacci/:size mit optionalen Queryparameter use_native
  4. Eine locust Konfigurationsdatei mit drei Tasks:
    1. Ruft /fibonacci/10 auf; mit Gewichtung 3
    2. Ruft /fibonacci/20 auf; mit Gewichtung 2
    3. Ruft /fibonacci/30 auf; ohne Gewichtung
    4. Verteilt über 100 User mit 1 Ramp User pro Sekunde
  5. Eine locust Konfigurationsdatei mit drei Tasks (für die Rust Implementierung):
    1. Ruft /fibonacci/10?use_native=true auf; mit Gewichtung 3
    2. Ruft /fibonacci/20?use_native=true auf; mit Gewichtung 2
    3. Ruft /fibonacci/30?use_native=true auf; ohne Gewichtung
    4. Verteilt über 100 User mit 1 Ramp User pro Sekunde

Allgemein wurde mit 1 Prozess und 1 Worker getestet.

Test-Machine

Lenovo ThinkPad P14s Gen 2i

  • Prozessor: 11th Gen Intel® Core™ i7-1165G7
  • RAM Größe: 32GiB

Dann schauen wir uns doch mal die Ergebnisse an!

Simple

Dieser Load-Test ruft den sehr einfachen JSON Response Endpoint auf und erhöht die User Zahlen stetig, bis zu einem Maximum von 10.000 Usern.

Wie zu erkennen ist, geht FastAPI (zumindest auf meinem Laptop) bereits mit 246.4 Requests pro Sekunde an seine Grenzen. So treten vermehrt Fehler auf bei denen die locust Requests nicht mehr (oder zu spät) verarbeitet wurden.

ConnectionResetError? - Oder wenn der Peer dich nicht mehr mag

Ein ConnectionResetError ist ein Netzwerkfehler, der auftritt, wenn die Gegenstelle (in diesem Fall der Server) eine bestehende TCP-Verbindung abrupt beendet, typischerweise durch Senden eines RST-Pakets (Reset). Dies ist keine ordnungsgemäße Beendigung (wie ein FIN-Paket) und signalisiert oft, dass etwas Unerwartetes passiert ist oder der Server die Verbindung nicht mehr verarbeiten kann.

Unter hoher Last kann ein Server überfordert sein. Dies kann verschiedene Ursachen haben: Erschöpfung von Systemressourcen (wie CPU, Speicher, Dateideskriptoren) oder eine Überlastung der Event-Loop, die für die Verarbeitung der asynchronen Operationen zuständig ist. Wenn die Event-Loop nicht schnell genug neue Verbindungen annehmen oder Daten auf bestehenden Sockets verarbeiten kann, können Timeouts auftreten oder der Server muss Verbindungen zwangsweise schließen, um Ressourcen freizugeben oder eine Überlastung zu verhindern.

Im Kontext von Python und ASGI-Servern wie Uvicorn (der von FastAPI genutzt wird) spielt die Art und Weise, wie Python Netzwerk-I/O handhabt, eine Rolle. Obwohl Python mit asyncio und ASGI asynchrone Operationen ermöglicht und theoretisch viele Verbindungen gleichzeitig verwalten kann, während auf I/O gewartet wird, gibt es Grenzen. Die Ausführung von Python-Code selbst unterliegt dem Global Interpreter Lock (GIL), der verhindert, dass mehrere native Threads gleichzeitig Python-Bytecode auf mehreren CPU-Kernen ausführen. Bei sehr hoher Last, selbst wenn die Endpoints I/O-gebunden sind (wie das einfache JSON-Response), kann die schiere Menge an Kontextwechseln, das Scheduling der Coroutinen und die kurze Zeit, die jede Anfrage im Python-Code verbringt (auch wenn es nur das Serialisieren des JSONs ist), dazu führen, dass die Event-Loop überlastet wird. Der Serverprozess verbringt zu viel Zeit mit der Ausführung von Python-Code (auch wenn er asynchron ist), um schnell genug auf neue oder bestehende Socket-Ereignisse zu reagieren.

Die ConnectionResetErrors in diesem Test zeigen, dass FastAPI (bzw. die zugrundeliegende Python/Uvicorn-Schicht) schon recht früh an seine Grenzen stößt. Die Event-Loop kann die eingehenden Anfragen nicht schnell genug verarbeiten, was dazu führt, dass der Server die Verbindungen zurücksetzt, anstatt sie ordnungsgemäß zu bedienen. Dies ist ein Indikator dafür, dass die Python-Runtime unter dieser spezifischen extremen Last zum Engpass wird. Während Robyn, das eine Rust-Runtime ohne GIL nutzt, diese Art von Engpass bei der Verarbeitung von Netzwerkverbindungen besser umschiffen können sollte.

Das Load Test Ergebnis für Robyn sieht dagegen deutlich performanter aus:

Was sehen wir? Nicht nur keine Failures (da alle Requests verarbeitet werden konnten) sondern auch durch die Bank schnellere Antwortzeiten! Spannend, aber nun zu den Load-Tests die eine Größere Herausforderung darstellen.

Fibonacci

Hier direkt die Ergebnisse (links FastAPI, rechts Robyn):

Python Fibonacci Vergleich

Wie wir sehen können, ist Robyn in den Antwortzeiten um ein paar Millisekunden besser als FastAPI. Auch trat hier unter FastAPI ein einziger Request Fail auf:

FastAPI Python Fibonacci Fail

Interessanterweise trat dieser zwischen 25 und 27 Requests per Second (RPS) auf und kam dann nie wieder vor. Dies kann also durchaus ein Ausreißer gewesen und auf meine nicht für API Hosting ausgelegte Hardware zurückzuführen sein.

Aber: Robyn unterstützt ja auch noch Rust nativen Code. Wie sieht es denn hier aus?

Python vs. native Fibonacci Vergleich

Das Ergebnis? Drastisch.

Spaß bei Seite, wie wir sehen können sind die Antwortzeiten in der (lange nicht optimierten) Rust Implementierung fast verschwindend gering. Hier die locust Zusammenfassung:

Native Fibonacci Response Time Stats

Hier fällt auf: Eine größere Fibonacci Zahl anzufordern scheint im Mittel und Maximum weniger Zeit als kleinere zu brauchen? Eine mögliche Erklärung hierfür könnte sein, dass der "Handover" von Python an Rust (und zurück von Rust an Python) die meiste Zeit in Anspruch nimmt.

Zusammenfassung

Wir haben FastAPI und Robyn mit einem simplen JSON-Endpoint sowie einem komplexeren Fibonacci-Endpoint unter Last getestet.

  • FastAPI erreicht auf meinem Laptop etwa 246 RPS, dann treten vermehrt Fehler auf.
  • Robyn bleibt auch bei 10.000 Usern stabil – schneller und ohne Fehler.
  • Bei der Fibonacci-Berechnung (Python) ist Robyn um ein paar Millisekunden flotter, während FastAPI bei 25–27 RPS einen Ausreißer zeigt.
  • Mit Rust-nativem Code in Robyn sehen wir eine drastische Verbesserung der Antwortzeiten – und sogar weniger Zeit bei größeren Fibonacci-Zahlen!

Fazit: Robyn skaliert besser als FastAPI, besonders bei hoher Last. Und Rust zeigt eindrucksvoll, wie viel mehr Performance möglich ist, wenn wir Python-Bottlenecks auslagern.

Wann nun welches Framework?

Die Wahl zwischen FastAPI und Robyn hängt von den spezifischen Anforderungen deines Projekts ab:

FastAPI ist ideal für:

  • Projekte mit komplexen Data Klassen
  • Teams, die strikte Typisierung bevorzugen
  • Anwendungen mit umfangreichen API-Dokumentationsanforderungen
  • Projekte, die eine etablierte Community und viele Ressourcen benötigen

Robyn eignet sich besser für:

  • Einfachere API-Projekte
  • Teams, die sich mehr Flexibilität bei der Implementierung wünschen
  • Projekte mit spezifischen Performance-Anforderungen, welche mit nativer Rust Integration und Runtime "heraus gequetscht" werden kann

Fazit

Sowohl FastAPI als auch Robyn sind moderne, leistungsstarke API-Frameworks, die unterschiedliche Stärken haben. FastAPI bietet eine umfassendere Lösung mit starker Typisierung und Validierung, während Robyn mehr Flexibilität und einen minimalistischen Ansatz bietet. Die endgültige Wahl sollte von den spezifischen Anforderungen deines Projekts abhängen.


FAQ – Häufige Fragen zur richtigen Framework Wahl

Welches Framework bietet bessere Performance?

Robyn zeigt in den Performance-Tests bessere Ergebnisse, besonders bei einfachen Endpoints und hoher Last. Allerdings bietet FastAPI eine ausgereiftere Ökosystem-Integration und Community-Unterstützung.

Kann ich Rust-Code in beiden Frameworks verwenden?

Robyn bietet eine native Integration von Rust-Code durch seine Rust-Runtime, während FastAPI dies nicht direkt unterstützt. Bei FastAPI müsste man auf traditionelle CPython-FFIs zurückgreifen.

Welches Framework ist besser für komplexe Datenmodelle geeignet?

FastAPI ist besser für komplexe Datenmodelle geeignet, da es Pydantic für Validierung und Serialisierung nutzt und eine strikte Typisierung bietet. Robyn bietet hier mehr Flexibilität, aber weniger vordefinierte Strukturen.

Wie unterscheiden sich die ORM-Möglichkeiten?

FastAPI bietet native Integration mit SQLAlchemy, Tortoise ORM und SQLModel. Robyn hat keine native ORM-Integration, erlaubt aber die Verwendung von Rust ORMs und bietet mehr Flexibilität bei der Datenbankwahl.

Für welche Art von Projekten ist welches Framework besser geeignet?

FastAPI eignet sich besser für komplexe Projekte mit umfangreichen API-Dokumentationsanforderungen und strikter Typisierung. Robyn ist ideal für einfachere API-Projekte und Teams, die mehr Flexibilität und native Rust-Integration wünschen.


Hast du noch Fragen oder eine Meinung? Mit deinem GitHub Account kannst Du es uns wissen lassen...


Was unsere Kunden über uns sagen

Ofa Bamberg GmbHRainer Kliewe
Ludwig-Maximilians-Universität MünchenProf. Dr. Mario Haim
Deutsches MuseumGeorg Hohmann
Fonds Finanz Maklerservice GmbHNorbert Porazik
Technische Universität HamburgSören Schütt-Sayed
  • Ofa Bamberg GmbH
    Ofa Bamberg GmbH
    B2B Online-Shop | B2C Website | Hosting | Betreuung | Security
    Rainer Kliewe
    © Ofa Bamberg GmbH
    Blueshoe betreut uns und unsere Webapplikationen seit vielen Jahren. Vom Online-Shop bis hin zu großen Teilen unseres Web-Umfelds hat sich das Unternehmen stets kompetent, verlässlich und vorausschauend gezeigt. Wir sind sehr zufrieden mit Blueshoe als Partner.
    Rainer KlieweGeschäftsführer
  • Ludwig-Maximilians-Universität München
    Ludwig-Maximilians-Universität München
    Plattformentwicklung | Hosting | Betreuung | APIs | Website
    Prof. Dr. Mario Haim
    Blueshoe hat unsere Forschungsdatenplattform Munich Media Monitoring (M3) entwickelt und uns hervorragend dabei beraten. Das Team hat unsere Anforderungen genau verstanden und sich aktiv in die Ausgestaltung der Software und der Betriebsumgebung eingebracht. Wir sind froh, dass auch Wartung und weiterführender Support in Blueshoes Händen liegen.
    Prof. Dr. Mario HaimLehrstuhlinhaber, Institut für Kommunikationswissenschaft und Medienforschung
  • Deutsches Museum
    Deutsches Museum
    Digitalisierung | Beratung | Datenbank-Optimierung | GraphQL | CMS
    Georg Hohmann
    Foto: Anne Göttlicher
    Im Rahmen eines komplexen Digitalisierungsprojekts für unsere Exponate-Datenbank war Blueshoe ein äußerst verlässlicher Partner. Sie haben uns nicht nur während des gesamten Projekts hervorragend beraten, sondern unsere Anforderungen perfekt umgesetzt. Dank ihrer Arbeit ist unsere Datenbank nun ein bedeutender Mehrwert für die weltweite wissenschaftliche Forschung.
    Georg HohmannLeiter Deutsches Museum Digital
  • Fonds Finanz Maklerservice GmbH
    Fonds Finanz Maklerservice GmbH
    Plattformentwicklung | Prozess-Systeme | Hosting | Betreuung | Zertifikate | Website
    Norbert Porazik
    © Fonds Finanz Maklerservice GmbH
    Blueshoe ist unsere verlängerte Werkbank für Entwicklung, Wartung und Support unserer Weiterbildungs- und Zertifizierungsplattformen. Das Team hat sich gründlich in unsere Abläufe eingearbeitet, und wir freuen uns, Blueshoe als zuverlässigen Partner an unserer Seite zu haben.
    Norbert PorazikGründer und Geschäftsführer
  • Technische Universität Hamburg
    Technische Universität Hamburg
    Plattformentwicklung | Beratung | Prozess-Systeme | Hosting | Website
    Sören Schütt-Sayed
    Seit 2019 unterstützt uns die Blueshoe GmbH tatkräftig bei der Entwicklung und Weiterentwicklung des "Digital Learning Lab" und der "Digital Learning Tools". Dank ihrer Beratung konnten wir von Anfang an auf eine zukunftssichere, moderne technische Struktur setzen. Die Zusammenarbeit ist reibungslos, und wir fühlen uns rundum gut betreut. Und davon profitieren dann auch die Lehrkräfte in Hamburg.
    Sören Schütt-SayedOberingenieur