Documentacao do cardisk

Esta documentacao foi organizada para web com base no pacote publicado no PyPI (cardisk 0.4.7, publicado em 4 de marco de 2026).

Introducao

cardisk e um framework Python para construir aplicacoes USSD, com API baseada em decoradores e fluxo de menu interativo.

  • Simple API - Decorator-based routing for clean screen handlers
  • Menu System - Built-in support for interactive menus with automatic navigation
  • Session Management - Automatic session handling with in-memory or Redis storage
  • Monitoring - Built-in Prometheus metrics endpoint
  • Error Handling - Robust error handling middleware
  • Type Safe - Full type hints support
  • Fast - High-performance runtime with Uvicorn

Instalacao

Instalacao de producao

pip install cardisk

Instalacao para desenvolvimento

pip install -e .

Quick Start

Crie um ficheiro app.py:

from cardisk import Cardisk, ussd

app = Cardisk()

@app.route("/")
def main_menu():
    ussd.menu("Welcome to Wolke Services", [
        ("Loans", "/loans"),
        ("Savings", "/savings"),
        ("Insurance", "/insurance")
    ])

@app.route("/loans")
def loans():
    ussd.menu("Loans Menu", [
        ("Apply for loan", "/loan/apply"),
        ("Check loan status", "/loan/status"),
        ("Repay loan", "/loan/repay")
    ])

@app.route("/loan/apply")
def loan_apply():
    ussd.screen(f"Enter loan amount for {ussd.msisdn}")
    ussd.next("/loan/confirm")

@app.route("/loan/confirm")
def loan_confirm():
    amount = ussd.input
    ussd.screen(f"Loan of ${amount} submitted successfully for {ussd.msisdn}")
    ussd.end()

Execute a aplicacao:

cardisk runserver app.py

Ou com Uvicorn:

uvicorn app:app.app --reload --port 8000

API

Setup da aplicacao

from cardisk import Cardisk, ussd

app = Cardisk()

Decorador de rota: @app.route()

@app.route("/path")
def handler():
    pass
  • As rotas devem iniciar com /.
  • Use / como ponto de entrada do menu principal.

Objeto ussd

Propriedades:

  • ussd.msisdn: numero do utilizador
  • ussd.session: ID da sessao atual
  • ussd.input: entrada do utilizador no passo anterior

Metodos principais:

ussd.menu("Main Menu", [
    ("Option 1", "/route1"),
    ("Option 2", "/route2")
])

ussd.screen("Hello!")
ussd.next("/verify-pin")
ussd.end()

Protocolo XML USSD

Formato da requisicao

<ussd>
    <type>1</type>
    <msisdn>254712345678</msisdn>
    <sessionid>unique-session-id</sessionid>
    <msg>user-input</msg>
</ussd>

Formato da resposta

<ussd>
    <type>2</type>
    <msg>Response text</msg>
</ussd>

Testes

Com cURL

1. Iniciar nova sessao:

curl -X POST http://localhost:8000/ \
  -H "Content-Type: application/xml" \
  -d '<ussd><type>1</type><msisdn>254712345678</msisdn><sessionid>test123</sessionid><msg></msg></ussd>'

2. Selecionar opcao de menu (ex.: opcao 1):

curl -X POST http://localhost:8000/ \
  -H "Content-Type: application/xml" \
  -d '<ussd><type>2</type><msisdn>254712345678</msisdn><sessionid>test123</sessionid><msg>1</msg></ussd>'

3. Enviar um input:

curl -X POST http://localhost:8000/ \
  -H "Content-Type: application/xml" \
  -d '<ussd><type>2</type><msisdn>254712345678</msisdn><sessionid>test123</sessionid><msg>500</msg></ussd>'

Com Python

import httpx

client = httpx.Client(base_url="http://localhost:8000")

# Start session
response = client.post("/", content="""
<ussd>
    <type>1</type>
    <msisdn>254712345678</msisdn>
    <sessionid>test123</sessionid>
    <msg></msg>
</ussd>
""", headers={"Content-Type": "application/xml"})

print(response.text)

# Continue session
response = client.post("/", content="""
<ussd>
    <type>2</type>
    <msisdn>254712345678</msisdn>
    <sessionid>test123</sessionid>
    <msg>1</msg>
</ussd>
""", headers={"Content-Type": "application/xml"})

print(response.text)

Exemplo de aplicacao

Exemplo completo disponivel em examples/mybank/main.py:

cd examples/mybank
cardisk runserver main.py

Ou com Uvicorn:

cd examples/mybank
uvicorn main:app.app --reload

Sessoes

Por padrao, cardisk usa armazenamento de sessao em memoria. Para producao com multiplas instancias, use Redis.

export CARDISK_USE_REDIS=true
export CARDISK_REDIS_URL=redis://localhost:6379/0

cardisk runserver app.py

Metricas

As metricas Prometheus estao disponiveis no endpoint /metrics.

curl http://localhost:8000/metrics

Metrica disponivel: cardisk_requests_total.

Docker

Build

docker build -t cardisk-app .

Run

docker run -p 8000:8000 cardisk-app

Com Redis

docker run -p 8000:8000 \
  -e CARDISK_USE_REDIS=true \
  -e CARDISK_REDIS_URL=redis://redis:6379/0 \
  cardisk-app

CLI

Criar novo projeto

cardisk new myproject

Executar servidor

cardisk runserver app.py --host 0.0.0.0 --port 8000

Uso avancado

Tratamento de erro personalizado

@app.route("/transfer")
def transfer():
    try:
        amount = float(ussd.input)
        if amount <= 0:
            ussd.screen("Invalid amount. Please try again.")
            ussd.next("/transfer")
        else:
            ussd.screen(f"Transfer of ${amount} successful!")
            ussd.end()
    except ValueError:
        ussd.screen("Invalid input. Please enter a number.")
        ussd.next("/transfer")

Formulario multi-step

@app.route("/register")
def register_name():
    ussd.screen("Enter your name:")
    ussd.next("/register/age")

@app.route("/register/age")
def register_age():
    name = ussd.input
    ussd.screen(f"Hello {name}! Enter your age:")
    ussd.next("/register/confirm")

@app.route("/register/confirm")
def register_confirm():
    age = ussd.input
    ussd.screen(f"Registration complete! Age: {age}")
    ussd.end()

Testing

Run tests

pytest

Run with coverage

pytest --cov=cardisk --cov-report=html

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

License

MIT License.

Support

For issues and questions, please open an issue on GitHub.