cenobites / flask-jsonrpc

Basic JSON-RPC implementation for your Flask-powered sites
BSD 3-Clause "New" or "Revised" License
289 stars 63 forks source link

Feature request: use Annotated type hint for per-field documentation #376

Open Talkless opened 1 year ago

Talkless commented 1 year ago

Annotated[] type hint (https://docs.python.org/3/library/typing.html#typing.Annotated) could be used to add per-field textual description later seen in API Browser.

Description taken from Annotated[] (or other implementation) type hint could be printed in popup dialog where you enter call parameters, like this:

@jsonrpc_client.method('object.list')
@jwt_required()
def object__list(
        with_archived: Annotated[Optional[bool], 'Include archived objects if set to true. Default: true.'] = True
        without_virtual: Annotated[Optional[bool], 'Exclude virtual objects if set to true. Default: true.'] = True
) -> Annotated[List[int], 'List of objects ids. May be empty.']:
"""Get list of objects, including archived (objects that are no longer used) and virtual (objects that do not have a tracking device, or is a virtual asset)."""
    # ...

image

Also, whole function signature could be printed together with field descriptions, so instead of this currently shown in API Browser:

object.list(with_archived: Boolean, without_virtual: Boolean) -> Object

we would get:

object.list(
    with_archived: Boolean, 
        Include archived objects if set to true. Default: true.

    without_virtual: Boolean
        Exclude virtual objects if set to true. Default: true

) -> Object
    List of objects ids. May be empty.
nycholas commented 1 year ago

It seems awesome! I need to explore more the features of Annotated decorator, 😄.

Talkless commented 1 year ago

I am afraid that might look verbose? Alternative would be to parse docstring, finding @param foo boolean This And That, but that will require to duplicate param name, type, so might get out of sync fast...

Annotated looks like more in-line solution though. More magic :) .

nycholas commented 1 month ago

I thinking of using the library annotated-types to give more metadata to typing.Annotated, it's the same as Pydantic is using and it will bring compatibility to the project (Pydantic models, pure Python classes, Python data classes, and TypeVar), besides that, in the future supports the PEP-746.

import typing as t

import annotated_types as at

@jsonrpc_client.method('object.list')
@jwt_required()
def object__list(
        age: t.Annotated[int, Gt(18)],  # Valid: 19, 20, ...
                                                          # Invalid: 17, 18, "19", 19.0, ...
        factors: list[t.Annotated[int, at.Predicate(is_prime)]],  # Valid: 2, 3, 5, 7, 11, ...
                                                                                                # Invalid: 4, 8, -2, 5.0, "prime", ...
        my_list: t.Annotated[list[int], at.Len(0, 10)],  # Valid: [], [10, 20, 30, 40, 50]
                                                                                 # Invalid: (1, 2), ["abc"], [0] * 20
        with_archived: t.Annotated[
            t.Optional[bool], 
            t.Doc('Include archived objects if set to true. Default: true.')
        ] = True
        without_virtual: t.Annotated[
            t.Optional[bool], 
            t.Doc('Exclude virtual objects if set to true. Default: true.')
        ] = True
) -> t.Annotated[t.List[int], t.Doc('List of objects ids. May be empty.')]:
"""Get list of objects, including archived (objects that are no longer 
   used) and virtual (objects that do not have a tracking device, or 
   is a virtual asset).
"""
    # ...

On Browser API, this metadata will be converted to a well-defined schema object (every context-specific metadata will be converted to an attribute on the schema) to be treated, validated, and processed by Browser API. In other words, for the project to support new context-specific metadata, it will need a new implementation (unfortunately).

Talkless commented 1 month ago

Looks good!

Talkless commented 1 month ago

metadata will be converted to a well-defined schema object

Maybe this implies users might be able to use some "third-party" API browsers in the future, as that popular Swagger, etc?

nycholas commented 4 weeks ago

@Talkless The project has support for OpenRPC, see here an example. It's closest to Swagger that we have for JSON RPC.