Quickstart

Decorators and function annotations indicate how a request will be handled.

Request Method

Uplink offers decorators that turn any method into a request definition. These decorators provide the request method and relative URL of the intended request: get, post, put, patch and delete.

The relative URL of the resource is specified in the decorator.

@get("users/list")

You can also specify query parameters in the URL.

@get("users/list?sort=desc")

Moreover, request methods must be bound to a Consumer subclass.

class MyApi(Consumer):
    @get("users/list")
    def list_users(self):
        """List all users."""

URL Manipulation

A request URL can be updated dynamically using URI template parameters. A simple URI parameter is an alphanumeric string surrounded by { and }.

To match the parameter with a method argument, either match the argument’s name with the alphanumeric string, like so

@get("group/{id}/users")
def group_list(self, id): pass

or use the Path annotation.

@get("group/{id}/users")
def group_list(self, group_id: Path("id")): pass

Query parameters can also be added.

@get("group/{id}/users")
def group_list(self, group_id: Path("id"), sort: Query): pass

For complex query parameter combinations, a mapping can be used:

@get("group/{id}/users")
def group_list(self, group_id: Path("id"), options: QueryMap): pass

Request Body

An argument’s value can be specified for use as an HTTP request body with the Body annotation:

@post("users/new")
def create_user(self, user: Body): pass

This annotation works well with the keyword arguments parameter (denoted by the ** prefix):

@post("users/new")
def create_user(self, **user_info: Body): pass

Form Encoded, Multipart, and JSON

Methods can also be declared to send form-encoded, multipart, and JSON data.

Form-encoded data is sent when form_url_encoded decorates the method. Each key-value pair is annotated with a Field annotation:

@form_url_encoded
@post("user/edit")
def update_user(self, first_name: Field, last_name: Field): pass

Multipart requests are used when multipart decorates the method. Parts are declared using the Part annotation:

@multipart
@put("user/photo")
def update_user(self, photo: Part, description: Part): pass

JSON data is sent when json decorates the method. The Body annotation declares the JSON payload:

@uplink.json
@uplink.patch("/user")
def update_user(self, **user_info: uplink.Body):
    """Update an authenticated user."""

Header Manipulation

You can set static headers for a method using the headers decorator.

@headers({
    "Accept": "application/vnd.github.v3.full+json",
    "User-Agent": "Uplink-Sample-App"
})
@get("users/{username}")
def get_user(self, username): pass

headers can be used as a class decorator for headers that need to be added to every request:

@headers({
    "Accept": "application/vnd.github.v3.full+json",
    "User-Agent": "Uplink-Sample-App"
})
class GitHub(Consumer):
    ...

A request header can be updated dynamically using the Header function parameter annotation:

@get("user")
def get_user(self, authorization: Header):
    """Get an authenticated user."""

Synchronous vs. Asynchronous

By default, Uplink uses the Requests library to make requests. However, the client parameter of the Consumer constructor offers a way to swap out Requests with another HTTP client:

github = GitHub(BASE_URL, client=...)

Notably, Requests blocks while waiting for a response from a server. For non-blocking requests, Uplink comes with optional support for asyncio and twisted. Checkout this example on GitHub for more.

Deserializing the Response

The converter parameter of the Consumer constructor accepts an adapter class that handles deserialization of HTTP response objects.

github = GitHub(BASE_URL, converter=...)

For instance, the MarshmallowConverter adapter turns JSON HTTP responses into Python objects using the marshmallow.Schema object. Checkout this example on GitHub for more.