Engineering

FastAPI for Python services that have to hold up

Not every backend should be the same language. When a service leans on Python's strengths — classification, natural-language work, the data and machine-learning ecosystem — we build it on FastAPI, and we hold it to the same typed, validated, tested bar as everything else.

When Python is the right call

We do not pick Python by default; we pick it when the work genuinely lives there. A service whose core job is machine learning, document or text classification, embeddings and similarity search, or heavy numerical work is a service where Python's libraries are the reason the thing is buildable at all, and forcing it into another runtime would be fighting the tools.

For a straightforward transactional API, we usually reach for Fastify in TypeScript instead — most backend patterns do not port cleanly between the two stacks, so the choice is made once, deliberately, per service rather than mixed inside one. The rule is honest fit, not language preference.

Typed and validated, the same as anywhere

FastAPI leans on Python type hints and Pydantic models to validate requests and responses at the boundary, which is the same guarantee we want from a TypeBox schema on the Fastify side — data is checked at the edge and the handler is written against known types. A dynamic language is not an excuse for an untyped service; it is a reason to be deliberate about where types are enforced.

Validation at the edge matters more, not less, for AI-heavy services, because the interesting failures are about shape and content — a payload that is subtly wrong, a field present but empty, an input too large. Catching those before they reach a model saves both a confusing result and the cost of the call that produced it.

Tested, including the parts that call a model

The same test-first discipline applies. Tests never run against real credentials or a live model in the suite — they use fake adapters and test-only secrets, so the suite is deterministic and cannot, for instance, quietly send real requests or real email. The deterministic seam around a model is part of the design, not an afterthought.

Argus, our AI-native operations console, is a Python service of this kind — incident classification, similar-incident search, and drafted postmortems — and it is honestly at proof-of-concept, not yet a live product, so we describe it as exactly that. When Python is the right backend for your problem, our approach is on AI-native app development.

Questions

People also ask

    When would you choose FastAPI over a Node backend?

    When the service's core work lives in Python — machine learning, classification, embeddings and similarity search, or heavy numerical work. For a straightforward transactional API we usually reach for Fastify in TypeScript instead.

    How do you test a service that calls an AI model?

    With fake adapters and test-only secrets, never real credentials or a live model in the suite, so tests stay deterministic and cannot send real requests. Validation at the edge catches malformed input before it reaches the model.