dreamfactory/df-cassandra
Apache Cassandra connector for DreamFactory, letting you register Cassandra as a data source and instantly expose tables through auto-generated REST APIs with schema discovery, role-based access control, and server-side scripting support.
dreamfactory/df-cassandra is not a standalone library — it is a DreamFactory service connector that plugs Apache Cassandra (or ScyllaDB) into a running DreamFactory instance and exposes it as auto-generated REST endpoints. You install it inside a DreamFactory host, not into your app.
Prerequisites
require in its composer.json)pecl install cassandra, or the ScyllaDB fork)Install into the host
composer require dreamfactory/df-cassandra
php artisan migrate # registers service type
php artisan vendor:publish --provider="DreamFactory\Core\Cassandra\ServiceProvider" # config/cassandra.php
php artisan config:clear && php artisan cache:clear
First place to look: config/cassandra.php (defaults for host/port/keyspace/protocol/consistency/timeouts) and src/Services/ (the DB handler that translates DreamFactory resource requests into CQL). Then the service's Swagger at /api/v2/{service}/_schema.
First use case — read-only table endpoint
host, port (9042), keyspace, credentials, protocol_version.GET verbs.curl -H "X-DreamFactory-Api-Key: $KEY" \
"https://df.local/api/v2/cassandra/_table/users?limit=20&filter=status='active'"
That’s the whole loop: one service definition gives you _table, _schema, records (POST/PUT/PATCH/DELETE), and an OpenAPI spec you can hand to a local LLM or enterprise app.
Service-per-keyspace, not per-cluster. A single service definition targets one keyspace. Multi-tenant or multi-keyspace designs should be one service per keyspace, grouped under role-scoped API keys rather than one giant service.
Governed LLM/agent access. This is the package’s real differentiator: point an agent at /api/v2/{service}/_spec (OpenAPI) or DreamFactory’s MCP endpoint, and Cassandra tables become tool calls. Lock it down with:
GET only for read agents)Filter syntax as your query interface. DreamFactory translates its filter= grammar into CQL WHERE. Design partition keys so these filters hit a partition:
# good — partition key present
filter=tenant_id=42 and created_at>'2025-01-01'
# bad — forces ALLOW FILTERING
filter=email='[email protected]'
Expose materialized views or denormalized tables to the API so agent queries stay partition-principled.
Server-side scripting for CQL you can’t express. Use pre/post-process events to normalize inputs or reshape responses:
// event: cassandra._table.users.get.pre_process
// force a partition key into every query
if (empty($event['request']['parameters']['filter'])) {
$event['request']['parameters']['filter'] = "tenant_id=" . $platform['session']['tenant_id'];
}
Same hook point for audit logging, PII redaction, and converting timeuuid/timestamp strings.
Composite primary keys. For /users/{id} verbs, verify how the connector assembles the record ID (often a concatenation of key fields). For multi-key tables, prefer filter= on the collection endpoint over /{id} — it’s more reliable and cacheable.
Schema caching is deliberate. _schema responses are cached; use ?refresh=true after ALTER TABLE, or php artisan cache:clear in your deploy script. Cache the schema in your client too — it rarely changes.
Containerize the driver. Bake the extension into the image so every dev matches prod:
RUN pecl install cassandra && docker-php-ext-enable cassandra
Version pinning. With 0 dependents and a small maintainer surface, pin exact tags (composer require dreamfactory/df-cassandra:6.x.y) and commit composer.lock. Treat upgrades as breaking until smoke-tested against _schema + a read + a write.
Integration tips
_proc sparingly; Cassandra has no stored procedures, so this path is largely unavailable.CQL ≠ SQL. This is the biggest day-to-day trap. Filters that a relational DreamFactory connector handles happily will fail or silently ALLOW FILTERING here:
JOIN, subqueries, or correlated lookupsORDER BY only on clustering columns within a single partitionLIKE requires a SASI/SAI-indexed columnGROUP BY only within a partition (C* 4.0+)OFFSET — the connector emulates it, which is slow on wide tablesPagination. limit is real. offset/deep pages will scan and time out. Prefer cursor-style queries on clustering columns (created_at > last_seen) or the driver’s paging state if the connector exposes it. Set client-side page sizes small (50–200).
Native driver pain. The DataStax PHP driver is effectively unmaintained; use the cassandra PECL extension or ScyllaDB’s fork. Alpine images need gmp, libuv, and often openssl-dev before pecl install succeeds — most “can’t connect” reports are actually failed extension builds, not config.
Protocol version mismatch. Defaults fail against modern clusters. DSE and Scylla commonly want protocol_version=4 (or v4); Astra/cloud needs TLS bundle + credentials. Symptom: connection refused or “unsupported protocol” in storage/logs/laravel.log.
Case sensitivity. Unquoted CQL identifiers fold to lowercase. A table created as "Users" must be referenced exactly, and the connector surfaces it as-is. If _schema shows a table but reads 404, suspect quoting.
Timeouts and consistency. Read timeouts on scans are common. Tune request_timeout / connect_timeout in service config; drop consistency from QUORUM to LOCAL_ONE for read-heavy agents if your SLA allows it.
Record IDs and composite keys. Auto-increment doesn’t exist — you must supply partition/clustering keys (often UUIDs or now() for timeuuid). The /{id} verbs assume the connector can reconstruct the full primary key; composite-key tables are the usual source of “record not found” bugs. Fall back to filters.
Schema staleness after DDL. A stale cached schema produces confusing errors (“column not found” on a column you just added). Always ?refresh=true post-migration.
Errors are wrapped. Driver exceptions surface as generic 500s in the API response. Enable APP_DEBUG=true locally and read storage/logs/laravel.log; the raw CQL and driver message are there.
Extension points, ranked by usefulness:
*.pre_process / *.post_process) — best lever for row scoping and reshapingconfig/cassandra.php — connection tuning onlySupport reality check. Zero stars and zero dependents means the DreamFactory team is the community. Pin versions, vendor the package if you need long-term stability, and test upgrades against a real cluster — not just composer update.
License is fine. Apache-2.0, commercial-friendly; retain the NOTICE file if you redistribute.
How can I help you explore Laravel packages today?