Skip to content

use decorateur to create route - #13

Merged
j03-dev merged 2 commits into
mainfrom
decorator
Mar 3, 2025
Merged

use decorateur to create route#13
j03-dev merged 2 commits into
mainfrom
decorator

Conversation

@j03-dev

@j03-dev j03-dev commented Mar 3, 2025

Copy link
Copy Markdown
Owner

Add method routes to get a list of routes and refactor all the example code.

Summary by CodeRabbit

  • New Features

    • Introduced a personalized greeting endpoint for improved user interaction.
    • Added middleware for enhanced request logging and token verification.
    • Expanded routing capabilities with flexible handling of content types and request data.
  • Refactor

    • Streamlined authentication and registration endpoints by leveraging external utilities.
    • Improved response processing and routing organization for clearer API interactions.

@coderabbitai

coderabbitai Bot commented Mar 3, 2025

Copy link
Copy Markdown
Contributor

Walkthrough

The pull request refactors the routing and authentication logic across multiple modules. In the Python examples, inline authentication functions have been removed in favor of external utility and middleware imports. The routing decorators and function signatures are updated, and a new endpoint is added. Two new modules, one for middleware and one for utilities, provide dedicated functionalities for logging, JWT handling, and password management. In the Rust code, the response body handling is streamlined while the Route struct is extended with new fields and updated constructor parameters to support flexible content types and data extraction.

Changes

File(s) Change Summary
examples/main.py Removed inline authentication functions and replaced them with imports from utils and middlewares. Updated route decorators using @post, adjusted function parameters, added a new endpoint (hello_world), and restructured the routing to distinguish between public and secured routes.
examples/middlewares.py and examples/utils.py Introduced new modules. In middlewares.py, added logger and jwt_middleware to handle request logging and JWT extraction. In utils.py, added functions for JWT creation/decoding and password hashing/verification with appropriate error handling.
src/handling/response_handler.rs Updated the setup_body function by removing the params argument and redundant iteration. The new logic directly checks for route.data and selects the request body based on the route's content_type, thereby streamlining the response body extraction process.
src/routing.rs Extended the Route struct with new fields (content_type and data), and updated the constructor and HTTP method functions (GET, POST, PUT, PATCH, DELETE) to accept optional content_type and data parameters. Also renamed the method decorator macro and added error handling for missing route data during invocation.

Sequence Diagram(s)

sequenceDiagram
    participant C as Client
    participant R as Router (pub_router/sec_router)
    participant L as Logger Middleware
    participant J as JWT Middleware
    participant H as Handler (e.g., login, register, hello_world)

    C->>R: Send HTTP Request
    R->>L: Forward request for logging
    L-->>R: Log details and forward
    alt Secured Route
      R->>J: Pass request for JWT extraction
      J-->>R: Validate token and attach user_id
    end
    R->>H: Call appropriate handler based on route
    H-->>R: Return response data
    R->>C: Send HTTP Response
Loading

Possibly related PRs

  • add chain middleware #9: Modifies middleware functions with a focus on the logger integration in the routing structure, directly relating to the changes in middleware and routing in this PR.

Poem

I'm a coding rabbit, hopping with sheer delight,
Skipping through routes, middleware shining bright.
My carrots are functions, crisp and well defined,
With utils and handlers perfectly aligned.
Debugging in the moonlight, I celebrate code so right!
🥕🐇 Happy hops in every commit!

✨ Finishing Touches
  • 📝 Generate Docstrings

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🔭 Outside diff range comments (1)
examples/main.py (1)

84-87: 💡 Verification agent

🧩 Analysis chain

Initialize AppData correctly since it's now a class that needs instantiation

Since AppData is now a class with a potential __init__ method, it needs to be instantiated properly.


🏁 Script executed:

#!/bin/bash
# Verify if AppData is used correctly in the server initialization

rg -A 3 $'server.app_data\(' examples/

Length of output: 185


Action Required: Instantiate AppData Before Passing to app_data()

  • In examples/main.py (lines 84–87), AppData is still passed as a class instead of an instance.

  • Please update the code from:

    server.app_data(AppData)

    to:

    server.app_data(AppData())

This modification ensures that the class's __init__ method is properly executed during initialization.

🧹 Nitpick comments (11)
examples/middlewares.py (2)

1-3: Authentication utilities should be imported with explicit relative imports

To improve clarity and prevent potential import conflicts, consider using explicit relative imports for local modules.

-from oxhttp import Status
-from utils import decode_jwt
+from oxhttp import Status
+from .utils import decode_jwt

5-10: Enhance logging with structured format for production readiness

While the current logger implementation works, consider enhancing it with structured logging for better integration with monitoring systems in production environments.

 def logger(request, next, **kwargs):
     method = request.method
     host = request.headers.get("host")
     uri = request.uri
-    print(f"method:{method} host:{host} uri:{uri}")
+    print(f"[LOG] method={method} host={host} uri={uri}")
     return next(**kwargs)
examples/utils.py (1)

12-16: Improve JWT error handling with more specific error responses

The current implementation returns None for all JWT validation errors, which doesn't provide enough information for debugging or client feedback.

 def decode_jwt(token: str):
     try:
         return decode(token, SECRET, algorithms=["HS256"])
-    except (ExpiredSignatureError, InvalidTokenError):
+    except ExpiredSignatureError:
+        print("Token expired")
+        return None
+    except InvalidTokenError:
+        print("Invalid token")
         return None
examples/main.py (3)

2-3: Use explicit relative imports for local modules

To improve code organization and prevent potential import conflicts, use explicit relative imports for local modules.

-from utils import hash_password, create_jwt, check_password
-from middlewares import logger, jwt_middleware
+from .utils import hash_password, create_jwt, check_password
+from .middlewares import logger, jwt_middleware

19-20: Add input validation for username and password

Consider adding more robust validation for username and password beyond just checking if they exist.

     username = user_input.get("username")
     password = user_input.get("password")

+    # Validate input
+    if not username or len(username) < 3:
+        return Status.BAD_REQUEST.into_response().body("Username must be at least 3 characters")
+    if not password or len(password) < 8:
+        return Status.BAD_REQUEST.into_response().body("Password must be at least 8 characters")

78-81: Consider adding documentation for the security router

The security router's purpose and requirements should be documented to clarify its usage.

+# Security router - all routes require JWT authentication
 sec_router = Router()
 sec_router.route(user_info)
 sec_router.middleware(logger)
 sec_router.middleware(jwt_middleware)
src/routing.rs (5)

20-36: Improved constructor with sensible defaults.

The updated constructor with optional parameters and sensible defaults makes the API more flexible and user-friendly. The default method "GET" and content-type "application/json" are appropriate choices.

However, there's a potential improvement in error handling:

The method no longer returns a PyResult, which means error conditions that might have been previously handled are now potentially ignored. Consider:

-    pub fn new(
-        path: String,
-        method: Option<String>,
-        content_type: Option<String>,
-        data: Option<String>,
-    ) -> Self {
+    pub fn new(
+        path: String,
+        method: Option<String>,
+        content_type: Option<String>,
+        data: Option<String>,
+    ) -> PyResult<Self> {
+        // Validate path format, method values, etc.
         Route {
             method: method.unwrap_or_else(|| "GET".to_string()),
             path,
             handler: Arc::new(Python::with_gil(|py| py.None())),
             args: Arc::new(Vec::new()),
             content_type: content_type.unwrap_or_else(|| "application/json".to_string()),
             data,
         }

38-58: Good validation of handler parameters.

The updated __call__ method now validates that if a data parameter is specified, the handler function must have a parameter with that name. This is a good validation step that will help developers catch mismatches between route definitions and handler functions.

However, the error message could be more informative:

-                let message = format!("Missing argument '{data}'");
+                let message = format!("Handler function is missing required parameter '{data}' needed for request body parsing");
                 return Err(PyException::new_err(message));

59-63: Consider optimizing clone usage.

The use of self.clone() in the Ok return value might be unnecessary performance overhead. Consider using field-by-field construction to avoid cloning the entire struct.

-        Ok(Self {
-            handler: Arc::new(handler),
-            args: Arc::new(args),
-            ..self.clone()
-        })
+        Ok(Self {
+            method: self.method.clone(),
+            path: self.path.clone(),
+            handler: Arc::new(handler),
+            args: Arc::new(args),
+            content_type: self.content_type.clone(),
+            data: self.data.clone(),
+        })

66-68: Consider improving the repr implementation.

The current implementation uses format!("{:#?}", self.clone()) which unnecessarily clones the entire struct before formatting it. This could be optimized.

-    fn __repr__(&self) -> String {
-        format!("{:#?}", self.clone())
-    }
+    fn __repr__(&self) -> String {
+        format!("{:#?}", self)
+    }

71-86: Improved macro naming and signature updates.

The macro rename from methods to method_decorator is more descriptive and clear. The updated function signatures with optional parameters align well with the constructor changes.

Consider adding documentation to explain the purpose of this macro:

+/// Macro that generates HTTP method decorator functions (get, post, put, patch, delete)
+/// These functions create Route instances with the appropriate HTTP method
 macro_rules! method_decorator {
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ba3e734 and 8ef5a5e.

📒 Files selected for processing (5)
  • examples/main.py (4 hunks)
  • examples/middlewares.py (1 hunks)
  • examples/utils.py (1 hunks)
  • src/handling/response_handler.rs (2 hunks)
  • src/routing.rs (4 hunks)
🧰 Additional context used
🪛 Ruff (0.8.2)
examples/middlewares.py

16-17: Use a single if statement instead of nested if statements

Combine if statements using and

(SIM102)

⏰ Context from checks skipped due to timeout of 90000ms (6)
  • GitHub Check: windows (x86)
  • GitHub Check: musllinux (armv7)
  • GitHub Check: windows (x64)
  • GitHub Check: musllinux (aarch64)
  • GitHub Check: musllinux (x86)
  • GitHub Check: musllinux (x86_64)
🔇 Additional comments (11)
examples/utils.py (2)

19-20: LGTM! Proper password hashing implementation

The password hashing implementation correctly uses bcrypt with salt generation.


23-24: LGTM! Secure password verification

The password verification implementation correctly uses bcrypt's built-in comparison function, which is resistant to timing attacks.

src/handling/response_handler.rs (2)

56-56: LGTM! Simplified function call by removing unnecessary parameter

The function signature has been updated to remove the unused params parameter, which is a good simplification.


94-99: LGTM! Improved request body handling based on content type

The implementation now correctly distinguishes between JSON and other content types, directing each to the appropriate handler.

examples/main.py (4)

16-17: LGTM! Good use of route decorators with body parameter specification

The implementation correctly uses the new decorator-based routing syntax with the data parameter to specify the body parameter name.


38-39: LGTM! Consistent use of route decorators for login endpoint

The login endpoint correctly uses the decorator-based routing with proper body parameter specification.


57-60: LGTM! New hello endpoint with path parameter

The new endpoint demonstrates good use of path parameters in the route decorator.


72-75: LGTM! Well-organized public router with middleware and routes

The implementation correctly structures the public router with middleware and routes.

src/routing.rs (3)

14-15: Good addition of content-type and data handling.

The addition of content_type and data fields to the Route struct enhances the flexibility of route definitions, allowing for more control over HTTP responses and request body parsing.


117-122: Good addition of bulk route registration.

The new routes method allows adding multiple routes at once, which is a useful convenience method that can help reduce code repetition in client applications.


125-136:

Details

❓ Verification inconclusive

Unsafe code needs careful review.

The find method contains unsafe code with transmute which requires careful review to ensure it's safe in all cases. While this wasn't changed in this PR, it's worth checking if there's a safer way to implement this functionality.


🏁 Script executed:

#!/bin/bash
# Find out if there are any safer alternatives to transmute in the Rust ecosystem

# Check if there are any other uses of transmute in the codebase
rg "transmute" --type rust --no-heading --line-number

# Look for examples of matchit::Router usage to see how others handle this
ast-grep --pattern $'router.at($path)' --lang=rust

Length of output: 465


Action Required: Verify Unsafe transmute Usage in src/routing.rs

The find method still employs an unsafe block with transmute (line 130) to convert the result from router.at(path) into a matchit::Match<'l, 'l, &Route>. Our repository-wide search shows that the same unsafety pattern exists in src/handling/request_handler.rs, and we didn’t find an immediately safer alternative through available examples. Please ensure that the types being transmuted are truly layout-compatible and consider documenting the rationale for using transmute or exploring a safe alternative if one becomes available.

  • Location to review:
    • src/routing.rs around line 130: let route: matchit::Match<'l, 'l, &Route> = unsafe { transmute(route) };

Comment thread examples/middlewares.py
Comment thread examples/utils.py
Comment thread examples/utils.py
Comment thread examples/main.py
Comment thread examples/main.py
Comment thread src/routing.rs

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (1)
examples/main.py (1)

62-65: ⚠️ Potential issue

Add error handling for user not found.

The user_info function should handle the case when a user is not found in the database.

 @get("/me")
 def user_info(user_id: int, app_data) -> Response:
     result = app_data.conn.execute("select * from user where id=?", (user_id,))
-    return Response(Status.OK, {"user": result.fetchone()})
+    user = result.fetchone()
+    if not user:
+        return Response(Status.NOT_FOUND, {"error": "User not found"})
+    return Response(Status.OK, {"user": user})
🧹 Nitpick comments (3)
examples/main.py (3)

2-3: Relative imports should be explicit.

The import statements use relative paths without explicitly indicating the relationship. This can cause import errors if the file is run from a different directory or imported from another module.

Consider using explicit relative imports:

-from utils import hash_password, create_jwt, check_password
-from middlewares import logger, jwt_middleware
+from .utils import hash_password, create_jwt, check_password
+from .middlewares import logger, jwt_middleware

16-17: Add type annotation for clarity.

The type annotation for user_input has been removed while it was present in the previous version as cred: dict. Maintaining type annotations improves code readability and assists development tools.

 @post("/register", data="user_input")
-def register(user_input, app_data):
+def register(user_input: dict, app_data: AppData):

38-39: Restore type annotation for consistency.

The app_data parameter is missing its type annotation while it was previously typed as AppData. Maintaining consistent type annotations across similar functions improves code readability.

 @post("/login", data="cred")
-def login(cred: dict, app_data):
+def login(cred: dict, app_data: AppData):
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8ef5a5e and d673b75.

📒 Files selected for processing (1)
  • examples/main.py (4 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (6)
  • GitHub Check: musllinux (armv7)
  • GitHub Check: windows (x86)
  • GitHub Check: musllinux (aarch64)
  • GitHub Check: windows (x64)
  • GitHub Check: musllinux (x86)
  • GitHub Check: musllinux (x86_64)
🔇 Additional comments (2)
examples/main.py (2)

68-70: LGTM: Database connection initialization in init method.

The database connection is now properly initialized in the __init__ method instead of as a class variable. This is a good practice that addresses a previous review comment.


86-86:

Details

❓ Verification inconclusive

Verify AppData initialization.

The server is configured with the AppData class itself, not an instance. Make sure this is the intended behavior for the framework.


🏁 Script executed:

#!/bin/bash
# Check how app_data is used elsewhere in the codebase
rg "app_data\(" --glob "*.py" -A 2 -B 2

Length of output: 245


Action Required: Confirm AppData Initialization Behavior

  • The code currently calls server.app_data(AppData) in examples/main.py, passing the class itself rather than an instance.
  • A code search indicates this is the sole usage of app_data in the repository. Please verify whether the framework is designed to receive the class (and instantiate it internally) or if an already instantiated object (i.e., AppData()) should be passed.
  • If passing the class is the intended behavior, consider adding a clarifying comment to avoid future confusion.

Comment thread examples/main.py
Comment on lines +57 to +59
@get("/hello/{name}")
def hello_world(name):
return f"Hello {name}"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

❓ Verification inconclusive

Add input validation for the name parameter.

The hello_world function doesn't validate the name parameter before using it in the response string. This could lead to potential issues if the name contains unexpected characters or is used in sensitive contexts.


🏁 Script executed:

#!/bin/bash
# Check if there are any existing validation routines in the codebase
rg -A 2 -B 2 'validate|sanitize' --glob '*.py'

Length of output: 48


Action: Implement input validation for the name parameter.

  • Location: examples/main.py, lines 57-59
  • The current implementation directly interpolates the name parameter into the response string without any checks.
  • A repository-wide search for validation or sanitization routines (using rg) returned no results, suggesting that no common input validation function is being applied.
  • Recommendation: Add specific input validations—such as using a regex whitelist or checking allowed characters—to ensure that unexpected or malicious input does not affect the response or propagate further issues.

Comment thread examples/main.py
Comment on lines +73 to +76
pub_router = Router()
pub_router.middleware(logger)
pub_router.routes([hello_world, login, register])
pub_router.route(static_files("./static", "static"))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add error handling for database connection.

While the router setup looks good, there's no error handling for the database connection in the AppData class. If the database file doesn't exist or the connection fails, the application will crash.

Consider adding error handling to the AppData class:

 class AppData:
     def __init__(self):
-        self.conn = sqlite3.connect("database.db")
+        try:
+            self.conn = sqlite3.connect("database.db")
+        except sqlite3.Error as e:
+            print(f"Database error: {e}")
+            self.conn = None
+
+    def __del__(self):
+        if hasattr(self, 'conn') and self.conn:
+            self.conn.close()

Committable suggestion skipped: line range outside the PR's diff.

@j03-dev
j03-dev merged commit ff1e60f into main Mar 3, 2025
@j03-dev
j03-dev deleted the decorator branch March 7, 2025 20:39
This was referenced May 23, 2025
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 this pull request may close these issues.

1 participant