Function Annotations¶
For programming in general, function parameters drive a function’s
dynamic behavior; a function’s output depends normally on its inputs.
With uplink
, function arguments parametrize an HTTP request,
and you indicate the dynamic parts of the request by appropriately
annotating those arguments with the classes detailed in this section.
Path¶
-
class
uplink.
Path
(name=None, type=None)[source]¶ Substitution of a path variable in a URI template.
URI template parameters are enclosed in braces (e.g.,
{name}
). To map an argument to a declared URI parameter, use thePath
annotation:class TodoService(object): @get("/todos/{id}") def get_todo(self, todo_id: Path("id")): pass
Then, invoking
get_todo
with a consumer instance:todo_service.get_todo(100)
creates an HTTP request with a URL ending in
/todos/100
.Note
Any unannotated function argument that shares a name with a URL path parameter is implicitly annotated with this class at runtime.
For example, we could simplify the method from the previous example by matching the path variable and method argument names:
@get("/todos/{id}") def get_todo(self, id): pass
Query¶
-
class
uplink.
Query
(name=None, encoded=False, type=None, encode_none=None)[source]¶ Set a dynamic query parameter.
This annotation turns argument values into URL query parameters. You can include it as function argument annotation, in the format:
<query argument>: uplink.Query
.If the API endpoint you are trying to query uses
q
as a query parameter, you can addq: uplink.Query
to the consumer method to set theq
search term at runtime.Example
@get("/search/commits") def search(self, search_term: Query("q")): """Search all commits with the given search term."""
To specify whether or not the query parameter is already URL encoded, use the optional
encoded
argument:@get("/search/commits") def search(self, search_term: Query("q", encoded=True)): """Search all commits with the given search term."""
To specify if and how
None
values should be encoded, use the optionalencode_none
argument:@get("/search/commits") def search(self, search_term: Query("q"), search_order: Query("o", encode_none="null")): """ Search all commits with the given search term using the optional search order. """
Parameters:
QueryMap¶
-
class
uplink.
QueryMap
(encoded=False, type=None)[source]¶ A mapping of query arguments.
If the API you are using accepts multiple query arguments, you can include them all in your function method by using the format:
<query argument>: uplink.QueryMap
Example
@get("/search/users") def search(self, **params: QueryMap): """Search all users."""
Parameters: encoded ( bool
, optional) – Specifies whether the parametername
and value are already URL encoded.
Header¶
-
class
uplink.
Header
(name=None, type=None)[source]¶ Pass a header as a method argument at runtime.
While
uplink.headers
attaches request headers values that are static across all requests sent from the decorated consumer method, this annotation turns a method argument into a dynamic request header.Example
@get("/user") def me(self, session_id: Header("Authorization")): """Get the authenticated user."""
To define an optional header, use the default value of None:
@get(“/repositories”) def fetch_repos(self, auth: Header(“Authorization”) = None):
“””List all public repositories.”””When the argument is not used, the header will not be added to the request.
Field¶
-
class
uplink.
Field
(name=None, type=None)[source]¶ Defines a form field to the request body.
Use together with the decorator
uplink.form_url_encoded
and annotate each argument accepting a form field withuplink.Field
.- Example::
@form_url_encoded @post("/users/edit") def update_user(self, first_name: Field, last_name: Field): """Update the current user."""
FieldMap¶
-
class
uplink.
FieldMap
(type=None)[source]¶ Defines a mapping of form fields to the request body.
Use together with the decorator
uplink.form_url_encoded
and annotate each argument accepting a form field withuplink.FieldMap
.Example
@form_url_encoded @post("/user/edit") def create_post(self, **user_info: FieldMap): """Update the current user."""
Part¶
-
class
uplink.
Part
(name=None, type=None)[source]¶ Marks an argument as a form part.
Use together with the decorator
uplink.multipart
and annotate each form part withuplink.Part
.Example
@multipart @put(/user/photo") def update_user(self, photo: Part, description: Part): """Upload a user profile photo."""
PartMap¶
-
class
uplink.
PartMap
(type=None)[source]¶ A mapping of form field parts.
Use together with the decorator
uplink.multipart
and annotate each part of form parts withuplink.PartMap
Example
@multipart @put(/user/photo") def update_user(self, photo: Part, description: Part): """Upload a user profile photo."""
Body¶
-
class
uplink.
Body
(type=None)[source]¶ Set the request body at runtime.
Use together with the decorator
uplink.json
. The method argument value will become the request’s body when annotated withuplink.Body
.Example
@json @patch(/user") def update_user(self, **info: Body): """Update the current user."""
Url¶
-
class
uplink.
Url
[source]¶ Sets a dynamic URL.
Provides the URL at runtime as a method argument. Drop the decorator parameter path from
uplink.get
and annotate the corresponding argument withuplink.Url
Example
@get def get(self, endpoint: Url): """Execute a GET requests against the given endpoint"""
Timeout¶
-
class
uplink.
Timeout
[source]¶ Passes a timeout as a method argument at runtime.
While
uplink.timeout
attaches static timeout to all requests sent from a consumer method, this class turns a method argument into a dynamic timeout value.Example
@get("/user/posts") def get_posts(self, timeout: Timeout() = 60): """Fetch all posts for the current users giving up after given number of seconds."""
Context¶
-
class
uplink.
Context
(name=None, type=None)[source]¶ Defines a name-value pair that is accessible to middleware at runtime.
Request middleware can leverage this annotation to give users control over the middleware’s behavior.
Example
Consider a custom decorator
@cache
(this would be a subclass ofuplink.decorators.MethodAnnotation
):@cache(hours=3) @get("users/user_id") def get_user(self, user_id) """Retrieves a single user."""
As its name suggests, the
@cache
decorator enables caching server responses so that, once a request is cached, subsequent identical requests can be served by the cache provider rather than adding load to the upstream service.Importantly, the writers of the
@cache
decorators can allow users to pass their own cache provider implementation through an argument annotated withContext
:@cache(hours=3) @get("users/user_id") def get_user(self, user_id, cache_provider: Context) """Retrieves a single user."""
To add a name-value pair to the context of any request made from a
Consumer
instance, you can use theConsumer.session.context
property. Alternatively, you can annotate a constructor argument of aConsumer
subclass withContext
, as explained here.