nanosdk.routing
¶
Declaring routes: get/post/..., Route, PaginatedRoute and Routes groups.
A route ties an HTTP method and path to a request model and a response type:
class Api(nanosdk.Client):
get_user = nanosdk.get("/users/{user_id}", request=GetUser, response=User)
On a client instance, api.get_user is a bound route you call like the request model's
constructor; the result is the decoded response. See Where fields go
for how request fields are placed.
Declaring routes¶
get
module-attribute
¶
Declare a GET route. Unmarked request fields go in the query string.
post
module-attribute
¶
Declare a POST route. Unmarked request fields become keys of a JSON body.
put
module-attribute
¶
Declare a PUT route. Unmarked request fields become keys of a JSON body.
patch
module-attribute
¶
Declare a PATCH route. Only fields the caller sets are sent (exclude_unset).
delete
module-attribute
¶
Declare a DELETE route. Unmarked request fields go in the query string.
route
¶
Verb
¶
Verb(method: str)
Declares routes for one HTTP method; nanosdk.get, nanosdk.post and so on.
Call it with a path and the request/response types to get a Route.
Overloads give the route precise types whether or not request and response are
given. Use route for methods without a ready-made verb.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
method
|
str
|
The HTTP method this verb declares. |
required |
Methods:
| Name | Description |
|---|---|
__call__ |
Declare a route for this verb's method. |
__call__
¶
__call__(
path: str,
*,
request: Callable[P, ReqT],
response: type[RespT],
headers: Mapping[str, str] | None = ...,
exclude_unset: bool | None = ...,
meta: Mapping[str, Any] | None = ...
) -> Route[P, ReqT, RespT]
__call__(
path: str,
*,
request: Callable[P, ReqT],
response: None = ...,
headers: Mapping[str, str] | None = ...,
exclude_unset: bool | None = ...,
meta: Mapping[str, Any] | None = ...
) -> Route[P, ReqT, None]
__call__(
path: str,
*,
request: Any = None,
response: Any = None,
headers: Mapping[str, str] | None = None,
exclude_unset: bool | None = None,
meta: Mapping[str, Any] | None = None
) -> Route[Any, Any, Any]
Declare a route for this verb's method.
Example
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
str
|
The path, relative to the client's |
required |
request
|
Any
|
The request model class; |
None
|
response
|
Any
|
The response type (see |
None
|
headers
|
Mapping[str, str] | None
|
Static headers sent with every call. |
None
|
exclude_unset
|
bool | None
|
Only send fields the caller set; defaults to |
None
|
meta
|
Mapping[str, Any] | None
|
Free-form data for client hooks. |
None
|
Returns:
| Type | Description |
|---|---|
Route[Any, Any, Any]
|
The route, typed from |
Route objects¶
Route
¶
Route(
method: str,
path: str,
*,
request: Callable[P, ReqT] | None = None,
response: Any = None,
headers: Mapping[str, str] | None = None,
exclude_unset: bool | None = None,
name: str | None = None,
meta: Mapping[str, Any] | None = None
)
One HTTP endpoint: method, path, request model and response type.
Usually made with get, post and friends rather than
directly. As a class attribute of a Client it's a descriptor: on
an instance it becomes a BoundRoute you call with the request
model's arguments.
The type parameters carry the typing end to end: P is the request model's
constructor signature (so calls are checked like constructing the model), ReqT the
request model and RespT the decoded response type.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
method
|
str
|
The HTTP method; any case. |
required |
path
|
str
|
The path, relative to the client's |
required |
request
|
Callable[P, ReqT] | None
|
The request model: a pydantic |
None
|
response
|
Any
|
The response type: anything pydantic's |
None
|
headers
|
Mapping[str, str] | None
|
Static headers sent with every call of this route. |
None
|
exclude_unset
|
bool | None
|
Only send fields the caller actually set. Defaults to |
None
|
name
|
str | None
|
The route's name; defaults to the attribute name it's assigned to. |
None
|
meta
|
Mapping[str, Any] | None
|
Free-form data for your client hooks, such as |
None
|
Attributes:
| Name | Type | Description |
|---|---|---|
method |
str
|
The upper-cased HTTP method. |
path |
The path template. |
|
request |
The request model class, or |
|
response |
The declared response type. |
|
headers |
dict[str, str]
|
Static headers. |
exclude_unset |
bool
|
Whether only explicitly set fields are sent. |
name |
The route's name (the attribute name on its class, once assigned). |
|
meta |
dict[str, Any]
|
Free-form data for client hooks. |
Methods:
| Name | Description |
|---|---|
bind |
Attach the route to a client, as accessing it on a client class does. |
with_prefix |
Return a copy with |
map |
Return a copy whose decoded response is passed through |
paginate |
Make the route iterable across pages. |
build_model |
Construct the request model from call arguments. |
encode |
Work out the URL, query, headers and body for a request model. |
parse |
Decode a successful response into the declared type, then apply any maps. |
bind
¶
bind(client: Client) -> BoundRoute[P, ReqT, RespT]
bind(
client: AsyncClient,
) -> AsyncBoundRoute[P, ReqT, RespT]
bind(client: Client | AsyncClient) -> Any
Attach the route to a client, as accessing it on a client class does.
For routes that aren't declared on the client's class:
get_user = nanosdk.get("/users/{user_id}", request=GetUser, response=User)
user = get_user.bind(api)(user_id=1)
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
client
|
Client | AsyncClient
|
The client to send through. |
required |
Returns:
| Type | Description |
|---|---|
Any
|
A bound route: call it, or use |
with_prefix
¶
map
¶
Return a copy whose decoded response is passed through fn.
The return type follows fn, so type checkers see the mapped type. Maps chain,
and run after validation, so fn receives the declared response type.
Example
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
fn
|
Callable[[RespT], U]
|
Function of the decoded response. |
required |
Returns:
| Type | Description |
|---|---|
Route[P, ReqT, U]
|
A new route; this one is unchanged. |
paginate
¶
paginate(
next: NextPage[ReqT, list[I], I],
) -> PaginatedRoute[P, ReqT, list[I], I]
paginate(
next: NextPage[ReqT, RespT, Any],
*,
items: Callable[[RespT], Iterable[I]]
) -> PaginatedRoute[P, ReqT, RespT, I]
Make the route iterable across pages.
Bound to a client, the result keeps the route's normal call (the first page)
and adds .iter() (every item, lazily) and .pages() (every
Page).
Example
# The response is a list: its elements are the items.
by_offset = nanosdk.get("/posts", request=ListPosts, response=list[Post]).paginate(
nanosdk.Offset("offset", limit="limit")
)
# The response wraps the list: say where the items are.
feed = nanosdk.get("/feed", request=Feed, response=FeedPage).paginate(
nanosdk.Cursor("next_cursor"), items=lambda page: page.data
)
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
next
|
Any
|
The pagination strategy: |
required |
items
|
Any
|
Extracts the item list from a decoded page. Optional when the
response type is already a |
None
|
Returns:
| Type | Description |
|---|---|
PaginatedRoute[Any, Any, Any, Any]
|
A paginated route wrapping this one. |
build_model
¶
Construct the request model from call arguments.
Raises:
| Type | Description |
|---|---|
ValidationError
|
If the arguments don't validate. |
TypeError
|
If the route has no request model but arguments were given. |
encode
¶
Work out the URL, query, headers and body for a request model.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
model
|
ReqT
|
An instance of the route's request model ( |
required |
Returns:
| Type | Description |
|---|---|
EncodedRequest
|
The encoded request, before client-level headers and auth are added. |
Raises:
| Type | Description |
|---|---|
TypeError
|
If the model's fields can't fill the route's path placeholders,
or the |
parse
¶
Decode a successful response into the declared type, then apply any maps.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
response
|
Response
|
A 2xx response. |
required |
Returns:
| Type | Description |
|---|---|
RespT
|
The decoded (and mapped) value. |
Raises:
| Type | Description |
|---|---|
ResponseValidationError
|
If the body doesn't match the response type. |
PaginatedRoute
¶
PaginatedRoute(
route: Route[P, ReqT, RespT],
*,
items: Callable[[RespT], Iterable[ItemT]],
next: NextPage[ReqT, RespT, ItemT]
)
A route plus the rules for walking its pages.
Made by Route.paginate.
Bound to a client it becomes a BoundPaginatedRoute
(or the async twin): calling it still fetches just the first page, and .iter(...)
/ .pages(...) walk all of them. ItemT is the type of each item.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
route
|
Route[P, ReqT, RespT]
|
The underlying route, which fetches one page. |
required |
items
|
Callable[[RespT], Iterable[ItemT]]
|
Extracts the item list from a decoded page. |
required |
next
|
NextPage[ReqT, RespT, ItemT]
|
The strategy that picks the next page's request. |
required |
Attributes:
| Name | Type | Description |
|---|---|---|
route |
The underlying route. |
|
items |
Extracts the item list from a decoded page. |
|
next_page |
The strategy that picks the next page's request. |
Methods:
| Name | Description |
|---|---|
bind |
Attach the paginated route to a client: |
with_prefix |
Return a copy whose underlying route has |
make_page |
Decode a response into a |
bind
¶
bind(
client: Client,
) -> BoundPaginatedRoute[P, ReqT, RespT, ItemT]
bind(
client: AsyncClient,
) -> AsyncBoundPaginatedRoute[P, ReqT, RespT, ItemT]
bind(client: Client | AsyncClient) -> Any
Attach the paginated route to a client: route.bind(api).iter(...).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
client
|
Client | AsyncClient
|
The client to send through. |
required |
Returns:
| Type | Description |
|---|---|
Any
|
A bound paginated route. |
with_prefix
¶
Return a copy whose underlying route has prefix prepended to its path.
Routes
¶
Base for a reusable group of routes, optionally under a common path prefix.
Mix groups into a Client and an
AsyncClient to share one set of route declarations between
a sync and an async SDK.
Example
Pass prefix= as a class keyword to prepend it to every route declared in the class
body.