Uplink Python Library

repository·master·Indexed 22 days ago

https://github.com/prkumar/uplink

A Python library inspired by Retrofit that allows developers to define structured, reusable API clients by turning HTTP endpoints into Python class methods using decorators and type hints. Uplink supports synchronous requests via RequestsClient and non-blocking requests using aiohttp or twisted. It features built-in authentication methods (BasicAuth, BearerToken, etc.), response and error handler callbacks, and optional integration with marshmallow and pydantic for automatic response deserialization into Python objects.

Tokens
17.4K
Snippets
58
Records
81
Agent score
77%

What's inside Uplink

  1. Core features of Uplink

    master

    Uplink provides several capabilities for building structured API clients:

    • Structured API Definition: Use decorators, type hints, and support for JSON, URL-encoded, and multipart request bodies.
    • Parameter Support: Easily handle URL parameter replacement, request headers, and query parameters.
    • Customizable HTTP Backend:
      • Support for non-blocking I/O via aiohttp and twisted.
      • Ability to supply your own session (e.g., requests.Session).
    • Serialization/Deserialization:
      • Support for pydantic models and marshmallow schemas.
      • Support for handling collections (e.g., a list of objects).
      • Custom converters for specialized object deserialization.
    • Extensibility:
      • Middleware support for custom response and error handling.
      • Plugin system (e.g., uplink-protobuf for protobuf support).
    • Authentication: Built-in Basic Authentication and compatibility with existing libraries like requests-oauthlib.
  2. Convert HTTP responses to Python objects with `returns.*`

    master

    Use the uplink.returns decorators to automatically deserialize HTTP response bodies into custom Python objects or specific formats. Available modules include:

    • uplink.returns.json: For JSON responses.
    • uplink.returns.from_json: For parsing JSON into specific types.
    • uplink.returns.schema: For validating against a schema.
  3. Handle collections of types in Uplink

    master

    Uplink allows you to define serialization support for a single type (e.g., a Task or User), and this support automatically extends to collections of that type, such as lists or dictionaries.

    To use this, annotate your method return type with uplink.types.List or uplink.types.Dict. If you are using Python 3.5+ with type hints, you can also use standard typing.List or typing.Dict instead of the uplink.types equivalents. This works for any serialization format supported by your consumer.

    Example workflow:

    1. Define your data model (e.g., a namedtuple).
    2. Implement a deserialization strategy for that model.
    3. Annotate the consumer method with typing.List[YourModel] to receive a list of parsed objects.
    import typing
    import collections
    from uplink import Consumer, returns, get
    
    # 1. Define the model
    Task = collections.namedtuple("Task", ["id", "name", "due_date"])
    
    class TaskApi(Consumer):
       @returns.json
       @get("tasks/{checklist}?due=today")
       # 2. Annotate with the collection type
       def get_pending_tasks(self, checklist) -> typing.List[Task]:
           pass
    
    # 3. Usage returns a list of Task objects
    # task_api.get_pending_tasks("home")
    # -> [Task(id=4139, ...), Task(id=4140, ...)]
  4. Omit names in annotations to adopt argument names

    master

    Several Uplink annotations allow you to specify a name parameter to map a function argument to a URI component (like a path parameter). If the argument name in your Python method matches the name used in the URI template, you can omit the name parameter.

    Supported annotations for this behavior include:

    • uplink.Path
    • uplink.Field
    • uplink.Part
    • uplink.Header
    • uplink.Query
    class GitHub(uplink.Consumer):
        # The argument 'username' matches the URI parameter '{username}'
        @uplink.get("users/{username}")
        def get_user(self, username: uplink.Path): 
            pass
  5. Convert collections using TypingConverter

    master

    Uplink can deserialize response bodies into collections (like lists or dictionaries) using the TypingConverter. This converter is automatically included.

    You can specify the collection type in your consumer method signatures using:

    1. Standard Python typing module type hints (e.g., List[User]).
    2. Proxy types defined in uplink.types (e.g., uplink.types.List).
  6. Configure request properties with decorators

    master

    Uplink uses decorators to manage various request properties. These decorators allow you to define how data is sent and how the request is handled. Key decorator groups include:

    • Data/Payload: uplink.json, uplink.form_url_encoded, uplink.multipart.
    • Request Metadata: uplink.headers, uplink.params.
    • Execution Control: uplink.timeout, uplink.args, uplink.inject.
    • Lifecycle/Error Handling: uplink.response_handler, uplink.error_handler.
  7. Parametrize HTTP requests using Function Annotations

    master
    In uplink, you define the dynamic parts of an HTTP request (such as path segments, query parameters, headers, or request bodies) by annotating function arguments with specific classes. These annotations tell uplink how to map the provided Python arguments into the corresponding parts of the outgoing HTTP request.
  8. Deserialize JSON API responses into Python objects using Marshmallow

    master

    You can use Uplink in conjunction with marshmallow to automatically convert JSON API responses into well-defined Python objects. This allows your application logic to interact with resources using attributes and methods rather than raw dictionary keys.

    To implement this pattern:

    1. Define marshmallow schemas that match the API response structure.
    2. Use these schemas in your Uplink service method return types to trigger deserialization.
  9. Use built-in Marshmallow and Pydantic converters

    master

    Uplink provides optional support for marshmallow and pydantic to handle serialization and deserialization.

    Starting with version v0.5, if marshmallow is installed in your environment, the MarshmallowConverter is automatically included.

    Starting with version v0.9.2, if pydantic is installed, the PydanticConverter is automatically included.

    You do not need to explicitly pass these to the converter parameter of the uplink.Consumer constructor if they are installed.

  10. Synchronous vs. Asynchronous Clients

    master

    Uplink supports both synchronous and asynchronous request patterns. While the default Requests client is blocking (synchronous), you can use uplink.AiohttpClient to enable non-blocking (asynchronous) requests via aiohttp.

    from uplink import AiohttpClient
    
    git_hub = GitHub(BASE_URL, client=AiohttpClient())
  11. Install Uplink with non-blocking client support

    master

    Uplink supports optional extras for non-blocking HTTP requests using twisted or aiohttp. You can install these features via pip using the bracket syntax. Note that aiohttp support requires Python 3.4 or above.

    # Install both twisted and aiohttp clients (requires Python 3.4+)
    $ pip install -U uplink[twisted, aiohttp]
    
    # Install support for twisted only
    $ pip install -U uplink[twisted]
    
    # Install support for aiohttp only
    $ pip install -U uplink[aiohttp]