Skip to main content

Overview

The prism-django package provides middleware for Django applications, integrating seamlessly with Django’s request/response cycle and middleware stack.

Middleware-Based

Integrates with Django middleware stack

ORM Compatible

Works with Django ORM and models

Admin Support

Compatible with Django Admin

Installation

pip install prism-django django

Quick Start

# settings.py
MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',

    # Add Prism middleware
    'prism_django.middleware.PrismPaymentMiddleware',
]

# Prism configuration
PRISM_CONFIG = {
    'API_KEY': 'dev-key-123',
    'BASE_URL': 'https://prism-api.test.1stdigital.tech',
    'DEBUG': True,
    'ROUTES': {
        '/api/premium/': {
            'price': 0.01,  # $0.01 USD
            'description': 'Premium API'
        }
    }
}

# views.py
from django.http import JsonResponse

def premium_view(request):
    # Access payer address
    payer = getattr(request, 'prism_payer', None)

    return JsonResponse({
        'message': 'Premium content',
        'payer': payer
    })

# urls.py
from django.urls import path
from . import views

urlpatterns = [
    path('api/premium/', views.premium_view),
]

Configuration

Settings.py

PRISM_CONFIG = {
    'API_KEY': 'your-api-key',
    'BASE_URL': 'https://prism-gateway.com',
    'DEBUG': False,
    'ROUTES': {
        '/api/premium/': {
            'price': 0.01,
            'description': 'Premium API'
        },
        '/api/weather/': {
            'price': 0.001,
            'description': 'Weather data'
        },
        '/api/data/*': {
            'price': 0.005,
            'description': 'Data API (wildcard)'
        }
    }
}

Route Protection

URL Patterns

# urls.py
from django.urls import path
from . import views

urlpatterns = [
    # Protected routes (configured in PRISM_CONFIG)
    path('api/premium/', views.premium_view),
    path('api/weather/', views.weather_view),

    # Free routes (not in PRISM_CONFIG)
    path('api/free/', views.free_view),
]

Accessing Payment Info

from django.http import JsonResponse

def premium_view(request):
    # Access payer address
    payer = getattr(request, 'prism_payer', None)
    # '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb'

    # Access payment object
    payment = getattr(request, 'prism_payment', None)

    if payment:
        return JsonResponse({
            'message': 'Premium data',
            'payer': payer,
            'network': payment.get('network'),
            'asset': payment.get('asset')
        })

    return JsonResponse({'message': 'No payment info'})

Settlement Validation

Django middleware intercepts responses to validate settlement:
# Internal implementation (automatic!)
class PrismPaymentMiddleware:
    def process_response(self, request, response):
        # Validate settlement
        settlement_result = core.settlement_callback(...)

        if not settlement_result or not settlement_result.get("success"):
            # ❌ Settlement failed
            return JsonResponse(
                {
                    'error': 'Payment settlement failed',
                    'details': settlement_result.get('errorReason')
                },
                status=402
            )

        # ✅ Settlement succeeded
        response['X-PAYMENT-RESPONSE'] = settlement_result['transaction']
        return response

Class-Based Views

from django.views import View
from django.http import JsonResponse

class PremiumAPIView(View):
    def get(self, request):
        payer = getattr(request, 'prism_payer', None)

        return JsonResponse({
            'message': 'Premium content',
            'payer': payer
        })

    def post(self, request):
        payer = getattr(request, 'prism_payer', None)

        # Process POST data
        data = request.POST

        return JsonResponse({
            'message': 'Data received',
            'payer': payer,
            'data': dict(data)
        })

Django REST Framework

# views.py
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status

class PremiumAPIView(APIView):
    def get(self, request):
        payer = getattr(request, 'prism_payer', None)

        return Response({
            'message': 'Premium content',
            'payer': payer
        })

# settings.py
INSTALLED_APPS = [
    # ...
    'rest_framework',
]

REST_FRAMEWORK = {
    'DEFAULT_RENDERER_CLASSES': [
        'rest_framework.renderers.JSONRenderer',
    ]
}

Testing

from django.test import TestCase, Client
import json

class PrismPaymentTests(TestCase):
    def setUp(self):
        self.client = Client()

    def test_payment_required_without_header(self):
        response = self.client.get('/api/premium/')

        self.assertEqual(response.status_code, 402)
        data = json.loads(response.content)
        self.assertTrue(data['paymentRequired'])

    def test_access_granted_with_valid_payment(self):
        payment = json.dumps({
            'scheme': 'eip3009',
            'signature': '0x' + '0' * 130
        })

        response = self.client.get(
            '/api/premium/',
            HTTP_X_PAYMENT=payment
        )

        self.assertEqual(response.status_code, 200)
        data = json.loads(response.content)
        self.assertIn('payer', data)

    def test_wildcard_route(self):
        response = self.client.get('/api/data/anything/')
        self.assertEqual(response.status_code, 402)

Production Deployment

Settings for Production

# settings.py
import os
from pathlib import Path

# Production settings
DEBUG = False
ALLOWED_HOSTS = os.getenv('ALLOWED_HOSTS', '').split(',')

# Prism configuration from environment
PRISM_CONFIG = {
    'API_KEY': os.environ['PRISM_API_KEY'],
    'BASE_URL': os.getenv('PRISM_BASE_URL', 'https://prism-gateway.com'),
    'DEBUG': DEBUG,
    'ROUTES': {
        '/api/premium/': {
            'price': 0.01,
            'description': 'Premium API'
        }
    }
}

# Security
SECURE_SSL_REDIRECT = True
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True

# CORS (if needed)
INSTALLED_APPS += ['corsheaders']
MIDDLEWARE.insert(0, 'corsheaders.middleware.CorsMiddleware')
CORS_ALLOWED_ORIGINS = os.getenv('CORS_ORIGINS', '').split(',')

WSGI Deployment (Gunicorn)

# Install Gunicorn
pip install gunicorn

# Run with Gunicorn
gunicorn myproject.wsgi:application \
    --bind 0.0.0.0:8000 \
    --workers 4 \
    --timeout 120 \
    --access-logfile - \
    --error-logfile -

Docker Deployment

FROM python:3.11-slim

WORKDIR /app

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

RUN python manage.py collectstatic --noinput

EXPOSE 8000

CMD ["gunicorn", "myproject.wsgi:application", "--bind", "0.0.0.0:8000"]

Type Hints

from typing import Optional, Dict, Any
from django.http import JsonResponse, HttpRequest

def premium_view(request: HttpRequest) -> JsonResponse:
    payer: Optional[str] = getattr(request, 'prism_payer', None)
    payment: Optional[Dict[str, Any]] = getattr(request, 'prism_payment', None)

    return JsonResponse({
        'message': 'Premium content',
        'payer': payer,
        'network': payment.get('network') if payment else None
    })

Next Steps