Skip to content

Commit

Permalink
feat: add bff handler context (#577)
Browse files Browse the repository at this point in the history
  • Loading branch information
brobro10000 authored Oct 31, 2024
1 parent 7aa0feb commit ac5c9eb
Show file tree
Hide file tree
Showing 6 changed files with 184 additions and 0 deletions.
Empty file.
8 changes: 8 additions & 0 deletions enterprise_access/apps/bffs/apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
""" App config for BFFs """

from django.apps import AppConfig


class BffsConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'enterprise_access.apps.bffs'
59 changes: 59 additions & 0 deletions enterprise_access/apps/bffs/context.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
"""
HandlerContext for bffs app.
"""
from enterprise_access.apps.bffs import serializers


class HandlerContext:
"""
A context object for managing the state throughout the lifecycle of a Backend-for-Frontend (BFF) request.
The `HandlerContext` class stores request information, loaded data, and any errors and warnings
that may occur during the request.
Attributes:
request: The original request object containing information about the incoming HTTP request.
user: The original request user information about hte incoming HTTP request.
data: A dictionary to store data loaded and processed by the handlers.
errors: A list to store errors that occur during request processing.
warnings: A list to store warnings that occur during the request processing.
enterprise_customer_uuid: The enterprise customer the user is associated with.
lms_user_id: The id associated with the authenticated user.
"""

def __init__(self, request):
"""
Initializes the HandlerContext with request information, route, and optional initial data.
Args:
request: The incoming HTTP request.
"""
self._request = request
self.data = {} # Stores processed data for the response
self.errors = [] # Stores any errors that occur during processing
self.warnings = [] # Stores any warnings that occur during processing
self.enterprise_customer_uuid = None
self.lms_user_id = None

@property
def request(self):
return self._request

@property
def user(self):
return self._request.user

def add_error(self, **kwargs):
"""
Adds an error to the context.
Output fields determined by the ErrorSerializer
"""
serializer = serializers.ErrorSerializer(data=kwargs)
serializer.is_valid(raise_exception=True)
self.errors.append(serializer.data)

def add_warning(self, **kwargs):
"""
Adds a warning to the context.
Output fields determined by the WarningSerializer
"""
serializer = serializers.WarningSerializer(data=kwargs)
serializer.is_valid(raise_exception=True)
self.warnings.append(serializer.data)
30 changes: 30 additions & 0 deletions enterprise_access/apps/bffs/serializers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
"""
Serializers for bffs.
"""
from rest_framework import serializers


class BaseBFFMessageSerializer(serializers.Serializer):
"""
Base Serializer for BFF messages.
Fields:
user_message (str): A user-friendly message.
developer_message (str): A more detailed message for debugging purposes.
"""
developer_message = serializers.CharField()
user_message = serializers.CharField()

def create(self, validated_data):
return validated_data

def update(self, instance, validated_data):
return validated_data


class ErrorSerializer(BaseBFFMessageSerializer):
pass


class WarningSerializer(BaseBFFMessageSerializer):
pass
86 changes: 86 additions & 0 deletions enterprise_access/apps/bffs/tests/test_context.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
"""
Text for the BFF context
"""
from django.test import RequestFactory, TestCase
from rest_framework.exceptions import ValidationError

from enterprise_access.apps.api_client.tests.test_constants import DATE_FORMAT_ISO_8601
from enterprise_access.apps.bffs.context import HandlerContext
from enterprise_access.apps.core.tests.factories import UserFactory
from enterprise_access.utils import _curr_date


class TestHandlerContext(TestCase):
def setUp(self):
super().setUp()
self.factory = RequestFactory()
self.mock_user = UserFactory()

def test_handler_context_init(self):
request = self.factory.get('sample/api/call')
request.user = self.mock_user
context = HandlerContext(request)

self.assertEqual(context.request, request)
self.assertEqual(context.user, self.mock_user)
self.assertEqual(context.data, {})
self.assertEqual(context.errors, [])
self.assertEqual(context.warnings, [])
self.assertEqual(context.enterprise_customer_uuid, None)
self.assertEqual(context.lms_user_id, None)

def test_handler_context_add_error_serializer(self):
request = self.factory.get('sample/api/call')
request.user = self.mock_user
context = HandlerContext(request)
expected_output = {
"developer_message": "No enterprise uuid associated to the user mock-uuid",
"user_message": "You may not be associated with the enterprise.",
}
# Define kwargs for add_error
arguments = {
**expected_output,
"status": 403 # Add an attribute that is not explicitly defined in the serializer to verify
}
context.add_error(
**arguments
)
self.assertEqual(expected_output, context.errors[0])

def test_handler_context_add_error_serializer_is_valid(self):
request = self.factory.get('sample/api/call')
request.user = self.mock_user
context = HandlerContext(request)
malformed_output = {
"developer_message": "No enterprise uuid associated to the user mock-uuid",
}
with self.assertRaises(ValidationError):
context.add_error(**malformed_output)

def test_handler_context_add_warning_serializer(self):
request = self.factory.get('sample/api/call')
request.user = self.mock_user
context = HandlerContext(request)
expected_output = {
"developer_message": "Heuristic Expiration",
"user_message": "The data received might be out-dated",
}
# Define kwargs for add_warning
arguments = {
**expected_output,
"status": 113 # Add an attribute that is not explicitly defined in the serializer to verify
}
context.add_warning(
**arguments
)
self.assertEqual(expected_output, context.warnings[0])

def test_handler_context_add_warning_serializer_is_valid(self):
request = self.factory.get('sample/api/call')
request.user = self.mock_user
context = HandlerContext(request)
malformed_output = {
"user_message": "The data received might be out-dated",
}
with self.assertRaises(ValidationError):
context.add_error(**malformed_output)
1 change: 1 addition & 0 deletions enterprise_access/settings/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ def root(*path_fragments):
'enterprise_access.apps.subsidy_access_policy',
'enterprise_access.apps.content_assignments',
'enterprise_access.apps.enterprise_groups',
'enterprise_access.apps.bffs',
)

INSTALLED_APPS += THIRD_PARTY_APPS
Expand Down

0 comments on commit ac5c9eb

Please sign in to comment.