-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1 from CameronSima/feature/validation
Feature/validation
- Loading branch information
Showing
17 changed files
with
499 additions
and
81 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
1. Out-of-the-box Real-time Capabilities | ||
WebSocket & Server-Sent Events (SSE) Support: Provide built-in support for WebSocket and SSE endpoints with seamless integration into the framework’s routing and middleware systems. | ||
Event Broadcasting and Pub/Sub: Integrate a simple pub/sub or event broadcasting system (using Redis or another broker) for real-time features like chat applications, live updates, or collaborative tools. | ||
|
||
2. First-class Support for Background Tasks and Workers | ||
Integrated Worker Queue: Include a built-in task queue system (similar to Celery) for background processing with async task support. Tasks could be defined in the same codebase with decorators and could run in separate worker processes. | ||
Job Scheduling: Native support for scheduling tasks with a cron-like syntax. | ||
|
||
3. Intuitive Error Handling and Debugging | ||
Error Tracing and Categorization: Introduce a built-in error-handling mechanism that categorizes errors, traces them to their origin, and provides detailed context in logs or error responses. | ||
Middleware for Debugging: Provide middleware that allows inspecting the internal state, dependencies, and the request lifecycle in real-time. | ||
|
||
4. Security Enhancements | ||
Built-in Security Middleware: Include robust security middleware by default for features like CSRF protection, CORS handling, rate limiting, and DDoS protection. | ||
Advanced Auth Integration: Built-in support for advanced authentication methods, including OAuth2, SAML, JWT, and OpenID Connect, with easy configuration. | ||
|
||
5. Optimized for Serverless and Edge Deployments | ||
Edge-optimized and Serverless-first: Design the framework to be easily deployable on serverless platforms (like AWS Lambda or Vercel) or edge networks, with minimal configuration and optimized cold-start times. | ||
Pre-rendering and Edge Caching: Integrate strategies for pre-rendering content and edge caching, making it more performant for static content delivery. | ||
|
||
6. Automatic API Documentation with Extensions | ||
Customizable and Dynamic Documentation: Provide a dynamic documentation system like Swagger or Redoc but with more customization options (themes, plugins) and interactive features, such as example requests/responses based on schema. | ||
API Versioning and Deprecation Notices: Automatically handle API versioning and provide built-in tools for deprecating old versions gracefully. | ||
|
||
7. Declarative Data Validation and Transformation | ||
Advanced Validation Framework: Go beyond Pydantic models by offering a more declarative approach for complex data validation, transformation, and coercion, including custom validation rules and error messages. | ||
|
||
8. GraphQL and gRPC Integration | ||
GraphQL Server with Subscriptions: Provide first-class support for building GraphQL servers with built-in support for subscriptions. | ||
gRPC Support: Offer built-in support for gRPC endpoints to enable high-performance RPCs for microservices. | ||
|
||
Schema-first Approach: Focus on a design-first approach where API definitions (using OpenAPI or GraphQL schema) drive the development process. | ||
Automatic Code Generation: Enable automatic code generation for client SDKs, server stubs, and documentation based on the schema. | ||
|
||
9. Data Streaming and Real-time Data Sync | ||
Built-in Data Streaming: Provide support for data streaming (using WebSockets or HTTP/2) and real-time data synchronization, which is particularly useful for collaborative applications. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
from .body import BodyParam, validate_body | ||
from .query import QueryParam, validate_query | ||
from .index import validate |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
from functools import wraps | ||
from ziplineio.request import Request | ||
from pydantic import ValidationError | ||
|
||
from ziplineio.validation.query import QueryParam | ||
|
||
|
||
class BodyParam(QueryParam): | ||
"""Alias Query param.""" | ||
|
||
pass | ||
|
||
|
||
def validate_body(*body_params): | ||
""" | ||
Decorator to validate body parameters. | ||
""" | ||
|
||
def decorator(handler): | ||
@wraps(handler) | ||
async def wrapper(req: Request, *args, **kwargs): | ||
errors = {} | ||
validated_body = {} | ||
|
||
for param in body_params: | ||
param_name = param.param | ||
value = req.body.get(param_name) | ||
if value is None: | ||
if param.required: | ||
errors[param_name] = "Missing required body parameter" | ||
else: | ||
try: | ||
validated_body[param_name] = param.validate(value) | ||
except (ValueError, ValidationError) as e: | ||
errors[param_name] = str(e) | ||
|
||
if errors: | ||
return {"errors": errors}, 400 | ||
|
||
# Attach validated body parameters to the request | ||
req.body = validated_body | ||
return await handler(req, *args, **kwargs) | ||
|
||
return wrapper | ||
|
||
return decorator if body_params else lambda req: decorator(lambda *_: None)(req) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
from ziplineio.request import Request | ||
|
||
|
||
def validate(*validators): | ||
def decorator(handler): | ||
async def wrapper(req: Request, ctx: dict): | ||
errors = {} | ||
validated_body = {} | ||
|
||
for validator in validators: | ||
validation_result = validator(req) | ||
validated_body.update(validation_result.get("validated", {})) | ||
errors.update(validation_result.get("errors", {})) | ||
|
||
if errors: | ||
return {"errors": errors}, 400 | ||
|
||
req.body = validated_body | ||
return await handler(req, ctx) | ||
|
||
return wrapper | ||
|
||
return decorator | ||
|
||
|
||
# # Example Pydantic model | ||
# class UserModel(BaseModel): | ||
# username: str | ||
# age: int | ||
|
||
|
||
# # Usage example with Pydantic model | ||
# @app.post("/") | ||
# @validate_body(BodyParam("user", UserModel)) | ||
# async def create_user_handler(req: Request, ctx: dict): | ||
# user = req.validated_body.get("user") | ||
# return {"user": user.dict()} # Access the validated Pydantic model instance | ||
|
||
|
||
# # Usage example with simple type validation | ||
# @app.get("/") | ||
# @validate_query(QueryParam("bar", str)) | ||
# async def test_handler(req: Request, ctx: dict): | ||
# bar = req.validated_query.get("bar") | ||
# return {"bar": bar} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
from functools import wraps | ||
import inspect | ||
from typing import Type, Union | ||
from pydantic import BaseModel, ValidationError | ||
from ziplineio.request import Request | ||
|
||
|
||
class QueryParam: | ||
def __init__( | ||
self, param: str, type: Union[Type, BaseModel] = str, required: bool = True | ||
): | ||
self.param = param | ||
self.type = type | ||
self.required = required | ||
|
||
def validate(self, value): | ||
if isinstance(self.type, type) and issubclass(self.type, BaseModel): | ||
try: | ||
# Use Pydantic model for validation | ||
model_instance = self.type.parse_obj(value) | ||
return model_instance | ||
except ValidationError as e: | ||
raise ValueError(f"Validation error for {self.param}: {e}") | ||
|
||
try: | ||
# Basic type casting | ||
return self.type(value) | ||
except ValueError: | ||
raise ValueError( | ||
f"Invalid type for {self.param}, expected {self.type.__name__}" | ||
) | ||
|
||
|
||
def validate_query(*query_params): | ||
""" | ||
Decorator to validate query parameters. | ||
""" | ||
|
||
def decorator(handler): | ||
# Use inspect to get the function signature and find the request parameter name | ||
signature = inspect.signature(handler) | ||
request_param_name = None | ||
|
||
# Find the parameter annotated with the Request type | ||
for param_name, param in signature.parameters.items(): | ||
if param.annotation == Request or isinstance( | ||
param_name, Request | ||
): # Look for the parameter with type `Request` | ||
request_param_name = param_name | ||
break | ||
|
||
if request_param_name is None: | ||
raise ValueError( | ||
"Handler function must have a parameter of type `Request`." | ||
) | ||
|
||
@wraps(handler) | ||
async def wrapper(*args, **kwargs): | ||
req = kwargs.get(request_param_name) | ||
|
||
errors = {} | ||
validated_query = {} | ||
|
||
for param in query_params: | ||
param_name = param.param | ||
value = req.query_params.get(param_name) | ||
if value is None: | ||
if param.required: | ||
errors[param_name] = "Missing required query parameter" | ||
else: | ||
try: | ||
validated_query[param_name] = param.validate(value) | ||
except (ValueError, ValidationError) as e: | ||
errors[param_name] = str(e) | ||
|
||
if errors: | ||
return {"errors": errors}, 400 | ||
|
||
# Attach validated query parameters to the request | ||
req.query_params = validated_query | ||
|
||
return await handler(*args, **kwargs) | ||
|
||
return wrapper | ||
|
||
return decorator if query_params else lambda req: decorator(lambda *_: None)(req) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.