Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement Pydantic Handling Decorator for Request/Response Validation for new VFolder API #3512

Open
seedspirit opened this issue Jan 21, 2025 — with Lablup-Issue-Syncer · 0 comments · May be fixed by #3511
Open
Assignees

Comments

@seedspirit
Copy link

Motivation  

  • Current pydantic request/response handling decorator lacks consistency due to mixed usage of aiohttp's web.Request and Pydantic models. So we need to standardize and maintain consistency in API interfaces
  • Current decorator combines both request/response handling and error handling, creating a need for separation of concerns

Required Features

  • Implement Pydantic middleware to handle all request components (body, query params, path variables) through Pydantic models instead of web.Request
  • Deploy as subapp middleware to isolate changes within new vFolder API application without affecting other API endpoints

Implementation (Detail)

As-Is

# 1. Global Auth Middleware
@web.Middleware
async def auth_middleware(request, handler):
    # 1) Initialize auth state in request
    request.update({
        "is_authorized": False,
        "user": None,
        "keypair": None
    })

    # 2) Check if handler requires auth
    if not handler.auth_required:
        return await handler(request)

    # 3) Process authorization and stor info in request obj
    if authenticated:
        request.update({
            "is_authorized": True,
            "user": user_info,
            "keypair": keypair_info
        })

# 2. Pydantic Param handler
def pydantic_params_api_handler(param_model, query_model = None):
    async def wrapped(request):
        try:
            # 1) Validate body/query params
            if request.has_body:
                params = param_model.validate(request.body)
                if query_model:
                    query_model = query_model.validate(request.query)
            else:
                params = param_model.valdiate(request.query)
            
            # 2) Exec handler
            result = await handler(request, params)
        
        # 3) If validation failed make custom msg and raise InvalidAPIParameters error(Custom error)
        except ValidationError as e:
            message = make_custom_msg(e)
            raise InvalidAPIParameters(message)
        
        # 4) Convert Pydantic Response model into aiohttp web.Response
        return web.json_response(result.model_dump(mode="json"))

    return wrapped

# 3. Usage Example
@auth_required  
@pydantic_params_api_handler(RequestModel)
async def handler(request, params):
   user = request["user"]  # Set from auth_middleware
   data = params  # Validated by pydantic

To-Be

Impact  

  • Consistent Request/Response processing logic across all API endpoints
  • Easy API documentation generation by using Pydantic

Testing Scenarios  

  • Verify all request components (body, params, path vars) are correctly processed through Pydantic models and validate error handling for each component
@seedspirit seedspirit self-assigned this Jan 21, 2025
@seedspirit seedspirit linked a pull request Jan 21, 2025 that will close this issue
7 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant