ActingWeb v3.1 Migration Guide

This guide helps you migrate from the legacy OnAWBase interface (removed in v3.1) to the modern ActingWebApp interface.

Overview of Changes

Version 3.1 represents a major architectural change:

  • Removed: Legacy OnAWBase interface completely

  • Removed: actingweb.on_aw module and OnAWBase class

  • Removed: ActingWebBridge compatibility layer

  • Changed: Handler constructors now accept hooks: HookRegistry instead of on_aw: OnAWBase

  • Required: Applications must now use the modern ActingWebApp interface exclusively

Migration Steps

Step 1: Replace OnAWBase Class

Before (Legacy - NO LONGER SUPPORTED):

from actingweb.on_aw import OnAWBase

class MyApp(OnAWBase):
    def get_properties(self, path, data):
        # Hide sensitive properties
        if path and path[0] == "email":
            return None
        return data

    def post_callbacks(self, name):
        if name == "webhook":
            # Handle webhook
            return True
        return False

After (Modern Interface - REQUIRED):

from actingweb.interface import ActingWebApp

app = ActingWebApp("my-app", "dynamodb", "myapp.com")

@app.property_hook("email")
def hide_email_property(actor, operation, value, path):
    if operation == "get":
        return None  # Hide email from external access
    return value

@app.callback_hook("webhook")
def handle_webhook(actor, name, data):
    # Handle webhook
    return {"status": "processed"}

Step 2: Update Handler Instantiation

Before:

from myapp import MyApp

my_onaw = MyApp()
handler = SomeHandler(webobj, config, on_aw=my_onaw)

After:

# Use the same app instance created above
handler = SomeHandler(webobj, config, hooks=app.hooks)

Step 3: Update Flask Integration

Before:

from flask import Flask
from actingweb.interface.integrations.flask_integration import FlaskIntegration
from actingweb.interface.bridge import ActingWebBridge

flask_app = Flask(__name__)
aw_app = ActingWebApp(...)
bridge = ActingWebBridge(aw_app)
integration = FlaskIntegration(aw_app, flask_app)

After:

from flask import Flask

flask_app = Flask(__name__)
aw_app = ActingWebApp(...)
integration = aw_app.integrate_flask(flask_app)

Hook Type Mapping

The new interface uses focused hook functions instead of monolithic class methods:

OnAWBase Method Mapping

Legacy OnAWBase Method

Modern Hook Equivalent

get_properties(path, data)

@app.property_hook("prop_name")

put_properties(path, old, new)

@app.property_hook("prop_name")

post_properties(prop, data)

@app.property_hook("prop_name")

delete_properties(path, old, new)

@app.property_hook("prop_name")

get_callbacks(name)

@app.callback_hook("callback_name")

post_callbacks(name)

@app.callback_hook("callback_name")

delete_callbacks(name)

@app.callback_hook("callback_name")

bot_post(path)

@app.app_callback_hook("bot")

post_subscriptions(sub, peerid, data)

@app.subscription_hook

delete_actor()

@app.lifecycle_hook("actor_deleted")

actions_on_oauth_success()

@app.lifecycle_hook("oauth_success")

get_methods(name)

@app.method_hook("method_name")

post_methods(name, data)

@app.method_hook("method_name")

get_actions(name)

@app.action_hook("action_name")

post_actions(name, data)

@app.action_hook("action_name")

Hook Function Signatures

Property Hooks

@app.property_hook("property_name")
def handle_property(actor: ActorInterface, operation: str, value: Any, path: List[str]) -> Any:
    # operation is one of: "get", "put", "post", "delete"
    if operation == "get":
        return value  # Transform or return None to reject
    elif operation == "put":
        return value  # Transform or return None to reject
    # ... handle other operations
    return value

Callback Hooks

@app.callback_hook("callback_name")
def handle_callback(actor: ActorInterface, name: str, data: Dict[str, Any]) -> Union[bool, Dict[str, Any]]:
    # Process callback
    return {"result": "processed"}  # or True/False

Application-Level Callback Hooks

@app.app_callback_hook("bot")
def handle_bot(data: Dict[str, Any]) -> Union[bool, Dict[str, Any]]:
    # No actor context - this is application-level
    return True

Method Hooks

@app.method_hook("method_name")
def handle_method(actor: ActorInterface, name: str, data: Dict[str, Any]) -> Optional[Dict[str, Any]]:
    # Process method call
    return {"result": "success"}

Action Hooks

@app.action_hook("action_name")
def handle_action(actor: ActorInterface, name: str, data: Dict[str, Any]) -> Optional[Dict[str, Any]]:
    # Process action
    return {"status": "executed"}

Lifecycle Hooks

@app.lifecycle_hook("actor_created")
def on_actor_created(actor: ActorInterface, **kwargs) -> None:
    # Initialize new actor
    actor.properties.created_at = str(datetime.now())

@app.lifecycle_hook("actor_deleted")
def on_actor_deleted(actor: ActorInterface, **kwargs) -> None:
    # Clean up before deletion
    pass

Subscription Hooks

@app.subscription_hook
def handle_subscription(actor: ActorInterface, subscription: Dict[str, Any], peer_id: str, data: Dict[str, Any]) -> bool:
    # Process subscription callback
    return True

Benefits of Migration

The new interface provides significant advantages:

Code Reduction
  • 95% less boilerplate code

  • Focused, single-purpose functions instead of monolithic classes

Better Developer Experience
  • Better type safety and IDE support

  • Easier testing and debugging

  • Self-documenting hook decorators

Architecture Benefits
  • Single source of truth for application logic

  • No more dual interface maintenance

  • Improved runtime performance without bridge layer overhead

  • Clean separation of concerns

Maintainability
  • Much simpler debugging without bridge layer abstraction

  • Direct hook execution in handlers

  • Eliminated potential for interface synchronization issues

Common Migration Issues

Type Errors

If you encounter type errors, ensure hook function signatures match exactly:

# Correct signature
@app.property_hook("email")
def handle_email(actor: ActorInterface, operation: str, value: Any, path: List[str]) -> Any:
    return value

Missing Imports

Update your imports:

# Remove these imports
# from actingweb.on_aw import OnAWBase
# from actingweb.interface.bridge import ActingWebBridge

# Use these instead
from actingweb.interface import ActingWebApp, ActorInterface

Handler Parameters

Ensure all handler instantiations use the new parameter:

# Old: on_aw=my_onaw_instance
# New: hooks=app.hooks
handler = MyHandler(webobj, config, hooks=app.hooks)

Need Help?

If you encounter issues during migration:

  1. Check that all hook function signatures match the documented patterns

  2. Ensure you’re using hooks=app.hooks in handler constructors

  3. Verify that property hooks return appropriate values (None to reject operations)

  4. Review the ActingWeb demo application for complete examples

The migration is straightforward and results in much cleaner, more maintainable code!