attach_instance Visual Guide
How to connect RoutingClass instances into hierarchies.
Core Concept
attach_instance lives on RoutingClass (not on Router). It does two things:
Sets the parent-child relationship (
child._routing_parent = self)Links child routers into parent routers (
parent_router._children[alias] = child_router)
graph LR
subgraph "RoutingClass (parent)"
P["self"]
PR["api (Router)"]
P --> PR
end
subgraph "RoutingClass (child)"
C["child"]
CR["api (Router)"]
C --> CR
end
P -- "_routing_parent" --> C
PR -- "_children['sales']" --> CR
style P fill:#e1f5fe
style C fill:#fff3e0
Scenario 1: One-to-One
Parent has 1 router, child has 1 router.
graph TB
subgraph "Parent"
PA["api (Router)"]
PA --- E1["health • entry"]
PA --- E2["status • entry"]
PA === S1["[sales]"]
end
subgraph "Child (vendite)"
CA["api (Router)"]
CA --- E3["ordini • entry"]
CA --- E4["fatture • entry"]
end
S1 --> CA
style PA fill:#bbdefb
style CA fill:#ffe0b2
style S1 fill:#c8e6c9,stroke:#2e7d32,stroke-width:2px
Syntax:
self.attach_instance(vendite, name="sales")
Access paths:
self.api.node("health")() # local entry
self.api.node("sales/ordini")() # child entry
self.api.node("sales/fatture")() # child entry
Rule: name= shortcut works only when child has exactly one router.
Scenario 2: One parent router, two child routers — child “dissolves”
Child’s routers are flattened into the parent’s single router. The child instance does not appear as an intermediate node.
graph TB
subgraph "Parent"
PA["api (Router)"]
PA --- E1["health • entry"]
PA === S1["[sales]"]
PA === S2["[tech]"]
end
subgraph "Child (vendite)"
CA["orders (Router)"]
CA --- E3["ordini • entry"]
CB["support (Router)"]
CB --- E4["ticket • entry"]
end
S1 --> CA
S2 --> CB
style PA fill:#bbdefb
style CA fill:#ffe0b2
style CB fill:#ffe0b2
style S1 fill:#c8e6c9,stroke:#2e7d32,stroke-width:2px
style S2 fill:#c8e6c9,stroke:#2e7d32,stroke-width:2px
Syntax:
self.attach_instance(vendite, router_api="orders:sales,support:tech")
Format: router_<parent_router>="<child_router>:<alias>,<child_router>:<alias>"
Access paths:
self.api.node("sales/ordini")() # from child.orders
self.api.node("tech/ticket")() # from child.support
Scenario 3: One parent router, two child routers — child “appears” with one router
Only one of the child’s routers is linked. The child appears as a node in the hierarchy, and any sub-routers of the linked router come along.
graph TB
subgraph "Parent"
PA["api (Router)"]
PA --- E1["health • entry"]
PA === S1["[sales]"]
end
subgraph "Child (vendite)"
CA["api (Router)"]
CA --- E3["ordini • entry"]
CA --- E4["fatture • entry"]
CA === SS["[statistiche]"]
CB["admin (Router)"]
CB --- E5["gestione • entry"]
end
subgraph "Grandchild"
GR["stats (Router)"]
GR --- E6["mensili • entry"]
GR --- E7["annuali • entry"]
end
S1 --> CA
SS --> GR
style PA fill:#bbdefb
style CA fill:#ffe0b2
style CB fill:#ffe0b2,stroke-dasharray: 5 5
style S1 fill:#c8e6c9,stroke:#2e7d32,stroke-width:2px
style SS fill:#c8e6c9
style GR fill:#f3e5f5
Syntax:
self.attach_instance(vendite, router_api="api:sales")
# Only vendite.api is linked. vendite.admin is NOT attached.
Access paths:
self.api.node("sales/ordini")() # child entry
self.api.node("sales/statistiche/mensili")() # grandchild entry
# self.api.node("???/gestione") -- NOT accessible (admin not linked)
Scenario 4: Two parent routers, one child router — parent chooses where
graph TB
subgraph "Parent"
PA["api (Router)"]
PA --- E1["health • entry"]
PA === S1["[users]"]
PB["admin (Router)"]
PB --- E2["dashboard • entry"]
end
subgraph "Child"
CA["api (Router)"]
CA --- E3["list • entry"]
CA --- E4["detail • entry"]
end
S1 --> CA
style PA fill:#bbdefb
style PB fill:#bbdefb
style CA fill:#ffe0b2
style S1 fill:#c8e6c9,stroke:#2e7d32,stroke-width:2px
Syntax:
self.attach_instance(child, router_api="api:users")
The kwarg router_api targets the parent’s api router. The child could be linked to admin instead:
self.attach_instance(child, router_admin="api:users")
Note: name= does NOT work here because the parent has multiple routers.
Scenario 5: Two parent routers, two child routers — cross-mapping
graph TB
subgraph "Parent"
PA["api (Router)"]
PA --- E1["health • entry"]
PA === S1["[sales]"]
PB["admin (Router)"]
PB --- E2["dashboard • entry"]
PB === S2["[management]"]
end
subgraph "Child (vendite)"
CA["orders (Router)"]
CA --- E3["ordini • entry"]
CB["mgmt (Router)"]
CB --- E4["gestione • entry"]
end
S1 --> CA
S2 --> CB
style PA fill:#bbdefb
style PB fill:#bbdefb
style CA fill:#ffe0b2
style CB fill:#ffe0b2
style S1 fill:#c8e6c9,stroke:#2e7d32,stroke-width:2px
style S2 fill:#c8e6c9,stroke:#2e7d32,stroke-width:2px
Syntax:
self.attach_instance(vendite,
router_api="orders:sales",
router_admin="mgmt:management",
)
Each router_<parent_router> kwarg specifies which child routers go into which parent router.
Access paths:
self.api.node("sales/ordini")() # parent.api -> child.orders
self.admin.node("management/gestione")() # parent.admin -> child.mgmt
Syntax Reference
name= shortcut (1:1)
self.attach_instance(child, name="alias")
Child must have exactly one router
Parent must have exactly one router
The child’s single router is linked under
aliasin the parent’s single router
router_* kwargs (any mapping)
self.attach_instance(child,
router_<parent_router>="<child_router>:<alias>,<child_router>:<alias>",
router_<parent_router>="<child_router>:<alias>",
)
Works with any number of parent/child routers
Multiple child routers can be linked to the same parent router (comma-separated)
Different child routers can go to different parent routers (separate kwargs)
Attach only (no routing)
self.attach_instance(child)
Sets
child._routing_parent = selfonlyNo routers are linked
Useful when you plan to link routers later or only need the parent chain for
ctxpropagation
include (on Router — low level)
Direct router-to-router or entry-alias linking.
Include a Router:
self._sys_router.include(swagger.api, name="swagger")
Links the source router as a child of this router
Sets
_routing_parenton the source’s ownerTriggers plugin inheritance
Use when the target is a nested router (e.g., created with
parent_router)
Include a RouterNode (entry alias):
fatture.api.include(
pagamenti.api.node("collega_a_fattura"),
name="collega_pagamento",
)
Creates an alias: same handler, visible from two paths
No copy — the original MethodEntry is shared
nameis required for RouterNode sources
detach_instance (on Router)
self.api.detach_instance(child)
Removes all of
child’s routers from this router’s_childrenClears
child._routing_parentStays on Router, not RoutingClass
Scenario 6: Entry Alias
The same handler declared in one service, visible in another’s tree.
graph TB
subgraph "Pagamenti"
PA["api (Router)"]
PA --- E1["lista_pagamenti • entry"]
PA --- E2["collega_a_fattura • entry"]
end
subgraph "Fatture"
FA["api (Router)"]
FA --- E3["lista_fatture • entry"]
FA -.- E4["collega_pagamento • alias"]
end
E4 -.->|"same handler"| E2
style PA fill:#bbdefb
style FA fill:#ffe0b2
style E4 fill:#f3e5f5,stroke:#7b1fa2,stroke-width:2px,stroke-dasharray: 5 5
Syntax:
fatture.api.include(
pagamenti.api.node("collega_a_fattura"),
name="collega_pagamento",
)
Access paths:
pagamenti.api.node("collega_a_fattura")(1, 2) # original
fatture.api.node("collega_pagamento")(1, 2) # alias — same handler
Decision Guide
flowchart TD
A["How many routers does the child have?"] --> B{"1 router"}
A --> C{"2+ routers"}
B --> D{"Parent has 1 router?"}
D -->|Yes| E["name='alias'"]
D -->|No| F["router_X='child_router:alias'"]
C --> G{"All go to same parent router?"}
G -->|Yes| H["router_X='a:alias1,b:alias2'"]
G -->|No| I["router_X='a:alias1'\nrouter_Y='b:alias2'"]
style E fill:#c8e6c9,stroke:#2e7d32
style F fill:#fff3e0,stroke:#ef6c00
style H fill:#fff3e0,stroke:#ef6c00
style I fill:#fff3e0,stroke:#ef6c00
Real-World Example
from genro_routes import RoutingClass, Router, route
class AuthService(RoutingClass):
def __init__(self):
self.api = Router(self, name="api")
@route("api")
def login(self, username: str, password: str):
return {"token": "..."}
class UserService(RoutingClass):
def __init__(self):
self.api = Router(self, name="api")
@route("api")
def list_users(self):
return ["alice", "bob"]
class Application(RoutingClass):
def __init__(self):
self.api = Router(self, name="api").plug("logging")
self.auth = AuthService()
self.users = UserService()
self.attach_instance(self.auth, name="auth")
self.attach_instance(self.users, name="users")
app = Application()
app.api.node("auth/login")("alice", "secret")
app.api.node("users/list_users")()