In production GraphQL APIs, tracking user actions and auditing database queries is a key security requirement. If you write auditing logic directly inside every resolver function, your codebase will contain duplicate code, making maintenance difficult. Ariadne supports custom middlewares that intercept the GraphQL execution loop, allowing developers to extract metadata, inspect queries, and log audits in a centralized layer.
By designing GraphQL middleware, you can inspect incoming queries and log database transactions.
1. Creating the GraphQL Audit Middleware
We write a middleware class that inspects query info, logs requests, and checks resolver execution speeds:
# middleware.py
import time
import logging
logging.basicConfig(level=logging.INFO)
def audit_middleware(resolver, obj, info, **kwargs):
# Retrieve user authentication context
context = info.context
user = context.get("user", "Anonymous")
# Track resolver execution duration
start_time = time.time()
result = resolver(obj, info, **kwargs)
duration = time.time() - start_time
# Log audit trail
logging.info(
f"User: {user} | Resolver: {info.field_name} | Target: {info.parent_type.name} | Duration: {duration:.4f}s"
)
return result
2. Registering Middleware in Ariadne
We pass the middleware to the schema execution endpoint: graphql_sync(schema, data, middleware=[audit_middleware]). This ensures that every resolver call is audited, providing a clean security audit trail.