Skip to main content

A wrapper around FastAPI to easily consume kafka messages as routes

Project description

FastAPI Kafka

This package is a wrapper around the amazing FastAPI package for introducing Kafka consumers as routes. No core FastAPI functionality has been altered and the documentation can be found here.

I drew inspiration for this package from working on a NestJS API using KafkaJS where kafka consumer topics are defined as controllers. It's an awesome pattern and super convienent to work with.

There is no doubt more work to do but it is a start.

Installation

Install FastAPI Kafka with pip

  pip install fastapi_kafka

Usage/Examples

Under the hood FastAPI Kafka uses AIOKafka to create a consumer. You define a consumer with the following, it matches the exact class inputs that AIOKafkaConsumer uses:

class KafkaConsumerConfig:
    loop: Optional[asyncio.AbstractEventLoop] = None
    bootstrap_servers: str = "localhost"
    client_id: Optional[str] = None
    group_id: Optional[str] = None
    group_instance_id: Optional[str] = None
    key_deserializer: Optional[Any] = None
    value_deserializer: Optional[Any] = None
    fetch_max_wait_ms: int = 500
    fetch_max_bytes: int = 52428800  # 50 MB
    fetch_min_bytes: int = 1
    max_partition_fetch_bytes: int = 1 * 1024 * 1024  # 1 MB
    request_timeout_ms: int = 40 * 1000  # 40 seconds
    retry_backoff_ms: int = 100
    auto_offset_reset: str = "latest"
    enable_auto_commit: bool = True
    auto_commit_interval_ms: int = 5000
    check_crcs: bool = True
    metadata_max_age_ms: int = 5 * 60 * 1000  # 5 minutes
    partition_assignment_strategy: tuple[Any, ...] = (RoundRobinPartitionAssignor,)
    max_poll_interval_ms: int = 300000  # 5 minutes
    rebalance_timeout_ms: Optional[int] = None
    session_timeout_ms: int = 10000  # 10 seconds
    heartbeat_interval_ms: int = 3000  # 3 seconds
    consumer_timeout_ms: int = 200  # 200 ms
    max_poll_records: Optional[int] = None
    ssl_context: Optional[ssl.SSLContext] = None
    security_protocol: str = "PLAINTEXT"
    api_version: str = "auto"
    exclude_internal_topics: bool = True
    connections_max_idle_ms: int = 540000  # 9 minutes
    isolation_level: str = "read_uncommitted"
    sasl_mechanism: str = "PLAIN"
    sasl_plain_password: Optional[str] = None
    sasl_plain_username: Optional[str] = None
    sasl_kerberos_service_name: str = "kafka"
    sasl_kerberos_domain_name: Optional[str] = None
    sasl_oauth_token_provider: Optional[Any] = None

Simple Example

Here's a full example running a local kafka server:

from typing import Any

from pydantic import BaseModel

from fastapi_kafka import FastAPIKafka
from fastapi_kafka.consumer import KafkaConsumerConfig


class SomeMessage(BaseModel):
    test: str


app = FastAPIKafka(
    kafka_consumer_config=KafkaConsumerConfig(
        bootstrap_servers="localhost:9092"
    )
)


@app.get("/")
def read_root():
    return {"Hello": "World"}


@app.consumer("test-topic")
async def read_item(item: Any):
    return item


@app.consumer("test-topic-model")
async def read_item_model(item: SomeMessage):
    return item

The FastAPIKafka can accept all standard constructor inputs as well.

To define a consumer topic you use @app.consumer("<topic name>"), you can define a kafka message as Any and it will return a UTF-8 decoded message when reading the item.

If you use JSON messages you can define a pydantic model to read it much the same as a regular http route, the message will be transformed into an instance of that model.

More Advanced Example (Using Upstash Kafka)

from typing import Any
from uuid import uuid4

from pydantic import BaseModel

from fastapi_kafka import FastAPIKafka, create_ssl_context
from fastapi_kafka.consumer import KafkaConsumerConfig


class SomeMessage(BaseModel):
    test: str


consumer_config = KafkaConsumerConfig(
    bootstrap_servers='example-us1-kafka.upstash.io:9092',
    sasl_mechanism='SCRAM-SHA-256',
    security_protocol='SASL_SSL',
    ssl_context=create_ssl_context(),
    sasl_plain_username='xxx',
    sasl_plain_password='xxx',
    client_id=f'consumer-{uuid4()}',
    group_id='consumer-group-api',
    auto_offset_reset='earliest',
)

app = FastAPIKafka(kafka_consumer_config=consumer_config)


@app.get("/")
def read_root():
    return {"Hello": "World"}


@app.consumer("test-topic")
async def read_item(item: Any):
    return item


@app.consumer("test-topic-model")
async def read_item_model(item: SomeMessage):
    return item

For security_protocol using SASL_SSL you must pass in a create_ssl_context().

For even more advanced configuration such as defining your own certificates, more information can be found here: AIOKafka SSL.

FastAPI Lifespan

One material change that was made to FastAPI was how Lifespan works. FastAPI Kafka initializes the Lifespan automatically to create the defined Kafka consumer, if you need additional start-up/shutdown behavior you can use the startup_functions or shutdown_functions when initializing the FastAPIKafka instance.

The startup_functions or shutdown_functions fields accept a list of synchronous or asynchronous functions to be executed before/after the yield in lifespan.

async def my_startup_actions():
    await do_something()
    do_something_sync()

async def my_shutdown_actions():
    await do_something_on_shutdown()

app = FastAPIKafka(
    kafka_consumer_config=consumer_config,
    startup_functions=[my_startup_actions],
    shutdown_functions=[my_shutdown_actions]
)

Contributing

Contributions are always welcome!

This is a new project and improvements are gladly welcomed.

Acknowledgements

  • This package is a wrapper around the amazing FastAPI package.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

fastapi_kafka-0.1.4.tar.gz (9.8 kB view details)

Uploaded Source

Built Distribution

fastapi_kafka-0.1.4-py3-none-any.whl (7.2 kB view details)

Uploaded Python 3

File details

Details for the file fastapi_kafka-0.1.4.tar.gz.

File metadata

  • Download URL: fastapi_kafka-0.1.4.tar.gz
  • Upload date:
  • Size: 9.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/5.1.1 CPython/3.11.9

File hashes

Hashes for fastapi_kafka-0.1.4.tar.gz
Algorithm Hash digest
SHA256 0ce936c0e8a5343b5239b17ae30d01355da41582dd25abef35e0f74968caf0de
MD5 2b7ccc6b0657461882233680783fff72
BLAKE2b-256 0474d5c4a53157085c2ac3939fa5ddc084a492e6ad9a0a147f0ae3ac2a615f78

See more details on using hashes here.

File details

Details for the file fastapi_kafka-0.1.4-py3-none-any.whl.

File metadata

File hashes

Hashes for fastapi_kafka-0.1.4-py3-none-any.whl
Algorithm Hash digest
SHA256 b3cbb23dc1876b7fe78a03f0923bc49f76d8381c6bd561ac2e1b12c15c451e85
MD5 32f69f2c7315726a77a41a8f09995ea5
BLAKE2b-256 cbee0911f82f71247dc21d81fea443169f0cc85c398fa4a5cabbffdc9b2f73b8

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page