Skip to content

Routing

Routing of Nexios is flexible and intuitive. Let's take a look.

The Basic Routing Example

python
from nexios import NexiosApp

app = NexiosApp()
@app.get("/") 
async def get_root(req, res):
    return {"message": "Hello, world!"}
🤔 How it Works
python
from nexios import NexiosApp
app = NexiosApp() 
@app.method("/path") 
async def get_root(req, res): 
    return {"message": "Hello, world!"}

Nexios provides flexible routing that supports both traditional decorators and alternative styles like direct route registration using functions or classes, giving developers full control over how they structure their APIs.

Routing With Decorators

python
from nexios import NexiosApp

# HTTP Methods
@app.get("/")
async def get_root(req, res):
    return {"message" : "Hello World"}
@app.post("/")
async def post_root(req, res):
    return {"message" : "Hello World"}

@app.put("/")
async def put_root(req, res):
    return {"message" : "Hello World"}

@app.delete("/")
async def delete_root(req, res):
    return res.text("DELETE /")

# Wildcard Route
@app.get("/wild/*/card")
async def wildcard_route(req, res):
    return {"message" : "Hello World"}

# Any HTTP Method
@app.route("/hello")
async def any_method(req, res):
    return {"message" : "Hello World"}

# Custom HTTP Method
@app.route("/cache", ["PURGE"])
async def purge_cache(req, res):
    return res.text("PURGE Method /cache")

# Multiple Methods
@app.route("/post", ["PUT", "DELETE"])
async def multiple_methods(req, res):
    return {"message" : "Hello World"}

⚠️ Warning

oute conflicts can occur if you register the same path with multiple handlers for overlapping methods without clarity. Ensure each route-method pair is unique or handled intentionally.

Other Route Methods

Nexios Provides Routes class for more complex routing needs. This Helps in grouping routes and makes the code more readable and maintainable.

python
from nexios.routing import Routes
from nexios import NexiosApp
app = NexiosApp()

async def dynamic_handler(req, res):
    return {"message" : "Hello World"}

app.add_route(Routes("/dynamic", dynamic_handler))  # Handles GET by default
app.add_route(Routes("/dynamic-post", dynamic_handler, methods=["POST"]))  # Handles POST

Tip 💡

you can also pass a list of Routes objects to NexiosApp to register multiple routes in a single call.

python

app = NexiosApp(routes = [
    Routes("/dynamic", dynamic_handler),  # Handles GET by default
    Routes("/dynamic-post", dynamic_handler, methods=["POST"]),  # Handles POST
])

The Routes Class in Detail

The Routes class is the core building block of Nexios routing. It encapsulates all routing information for an API endpoint, including path handling, validation, OpenAPI documentation, and request processing.

python
from nexios.routing import Routes

route = Routes(
    path="/users/{user_id}",
    handler=user_detail_handler,
    methods=["GET", "PUT", "DELETE"],
    name="user_detail",
    summary="User Detail API",
    description="Get, update or delete a user by ID",
    responses={
        200: UserResponse,
        404: Error_404
    },
    request_model=UserUpdate,
    middlewares=[auth_middleware, logging_middleware],
    tags=["users"],
    security=[{"bearerAuth": []}],
    operation_id="getUserDetail",
    deprecated=False,
    parameters=[
        Parameter(name="include_details", in_="query", required=False, schema=Schema(type="boolean"))
    ]
)

app.add_route(route)

Parameters

ParameterDescriptionTypeDefault
pathURL path pattern with optional parametersstrRequired
handlerRequest processing function/methodCallableRequired
methodsAllowed HTTP methodsList[str]["get", "post", "delete", "put", "patch", "options"]
nameRoute name (for URL generation)Optional[str]None
summaryBrief description for OpenAPI docsOptional[str]None
descriptionDetailed description for OpenAPI docsOptional[str]None
responsesResponse schemas or descriptionsOptional[Dict[int, Any]]None
request_modelPydantic model for request validationOptional[Type[BaseModel]]None
middlewaresRoute-specific middlewareList[Any][]
tagsOpenAPI tags for groupingOptional[List[str]]None
securitySecurity requirementsOptional[List[Dict[str, List[str]]]]None
operation_idUnique identifier for OpenAPIOptional[str]None
deprecatedMark route as deprecatedboolFalse
parametersAdditional parameters for OpenAPIList[Parameter][]
exclude_from_schemaHide from OpenAPI docsboolFalse
                                          |

Quick Tip 💡

the decorator and Routes takes the same arguments. 😁

Path Parameter

Path parameters allow you to capture dynamic segments of a URL. These parameters are extracted from the URL and made available to the route handler via the req.path_params object.

python
from nexios import NexiosApp
app = NexiosApp()
@app.get('/posts/{post_id}/comment/{comment_id}') 
async def get_post_comment(req, res):
   ...

This will match /posts/123/comment/456 and extract 123 and 456 as post_id and comment_id respectively.

You can access the path parameters using req.path_params object.

python
from nexios import NexiosApp
app = NexiosApp()
@app.get('/posts/{post_id}/comment/{comment_id}') 
async def get_post_comment(req, res):
   post_id = req.path_params.post_id
   comment_id = req.path_params.comment_id
   return {"message": f"post_id: {post_id}, comment_id: {comment_id}"}

Alternatively, you can use pass the path parameters to the handler directly using

python
from nexios import NexiosApp
app = NexiosApp()
@app.get('/posts/{post_id}/comment/{comment_id}') 
async def get_post_comment(req, res, post_id, comment_id):
   return {"message": f"post_id: {post_id}, comment_id: {comment_id}"}

Optional Route Parameters

To use optional parameters in Nexios, you can define them in your route Double:

py
from nexios import NexiosApp
app = NexiosApp()
@app.get('/posts/{post_id}') 
@app.get('/posts') 
async def get_post_comment(req, res):
   return {"message": f"post_id: {post_id}"}

Route Converters

Route converters in Nexios allow you to enforce specific types or patterns on dynamic segments of your routes. This ensures that only valid data is processed, improving the reliability and predictability of your API.

Built-in Converters

int – Matches an integer (whole number).

python
@app.get("/items/{item_id:int}")
async def get_item(req, res):
    item_id = req.path_params.item_id
    return res.text(f"Item ID: {item_id} (Integer)")
  • Matches: /items/42
  • Does Not Match: /items/applefloat – Matches a floating-point number.
python
@app.get("/price/{amount:float}")
async def get_price(req, res):
    amount = req.path_params.amount
    return res.text(f"Amount: {amount} (Float)")
  • Matches: /price/99.99
  • Does Not Match: /price/freepath – Matches any string, including slashes (/).
python
@app.get("/files/{filepath:path}")
async def read_file(req, res):
    filepath = req.path_params.filepath
    return res.text(f"File Path: {filepath}")
  • Matches: /files/documents/report.pdf
  • Does Not Match: (Almost always matches) uuid – Matches a valid UUID string.
python
@app.get("/users/{user_id:uuid}")
async def get_user(req, res):
    user_id = req.path_params.user_id
    return res.text(f"User ID: {user_id} (UUID)")
  • Matches: /users/550e8400-e29b-41d4-a716-446655440000
  • Does Not Match: /users/12345

string – Matches any string (default behavior).

python
@app.post("/person/{username:str}")
async def get_person(req, res):
    username = req.path_params.username
    return res.text(f"Username: {username}")
  • Matches: /person/anyname
  • Does Not Match: (Almost always matches)

Reverse Routing

You can also reverse route a path using the url_for method of the NexiosApp and Router instance.

python
from nexios import NexiosApp
app = NexiosApp()
@app.get('/posts/{post_id}/comment/{comment_id}', name='get_post_comment') 
async def get_post_comment(req, res):
    url = app.url_for('get_post_comment', post_id=123, comment_id=456)
    return res.text(url)

This will generate the URL /posts/123/comment/456

⚠️ Warning

To use the url_for method, you must have a name attribute set for your route.

Reverse Routing with Nested Routers

Sometimes, you may want to reverse route a path from a nested router. In such cases, you can use the url_for method of the parent router to generate the URL.

python
from nexios import NexiosApp
from nexios.routing import Router
app = NexiosApp()
v1_router = Router(prefix="/v1", name='v1') # Note the name attribute
router.get('/posts/{post_id}/comment/{comment_id}', name='get_post_comment') 
async def get_post_comment(req, res):
    url = app.url_for('v1.get_post_comment', post_id=123, comment_id=456)
    return res.text(url)

This will generate the URL /posts/123/comment/456

😎 Info

To use the url_for method, you must have a name attribute set for your route.

Using reverse in nested router is limited to only it children. You can use the request object for global reverse routing.

python
from nexios import NexiosApp
from nexios.routing import Router
app = NexiosApp()
v1_router = Router(prefix="/v1", name='v1') # Note the name attribute
router.get('/posts/{post_id}/comment/{comment_id}', name='get_post_comment') 
async def get_post_comment(req, res):
    url = req.app.url_for('v1.get_post_comment', post_id=123, comment_id=456)
    return res.text(url)

This will generate the URL /v1/posts/123/comment/456