wipac-rest-tools


Namewipac-rest-tools JSON
Version 1.7.3 PyPI version JSON
download
home_pagehttps://github.com/WIPACrepo/rest-tools
SummaryREST tools in python - common code for client and server
upload_time2024-05-01 17:53:14
maintainerNone
docs_urlNone
authorWIPAC Developers
requires_python<3.13,>=3.8
licenseMIT
keywords python rest tools utilities opentelemetry tracing telemetry wipac icecube
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            <!--- Top of README Badges (automated) --->
[![PyPI](https://img.shields.io/pypi/v/wipac-rest-tools)](https://pypi.org/project/wipac-rest-tools/) [![GitHub release (latest by date including pre-releases)](https://img.shields.io/github/v/release/WIPACrepo/rest-tools?include_prereleases)](https://github.com/WIPACrepo/rest-tools/) [![PyPI - License](https://img.shields.io/pypi/l/wipac-rest-tools)](https://github.com/WIPACrepo/rest-tools/blob/master/LICENSE) [![Lines of code](https://img.shields.io/tokei/lines/github/WIPACrepo/rest-tools)](https://github.com/WIPACrepo/rest-tools/) [![GitHub issues](https://img.shields.io/github/issues/WIPACrepo/rest-tools)](https://github.com/WIPACrepo/rest-tools/issues?q=is%3Aissue+sort%3Aupdated-desc+is%3Aopen) [![GitHub pull requests](https://img.shields.io/github/issues-pr/WIPACrepo/rest-tools)](https://github.com/WIPACrepo/rest-tools/pulls?q=is%3Apr+sort%3Aupdated-desc+is%3Aopen) 
<!--- End of README Badges (automated) --->
# rest-tools

This project contains REST tools in python, as common code for multiple other
projects under https://github.com/WIPACrepo.

All code uses python [asyncio](https://docs.python.org/3/library/asyncio.html),
so is fully asyncronous.

Note that both the client and server assume starting the asyncio loop
happens elsewhere - they do not start the loop themselves.

## Client

A REST API client exists under `rest_tools.client`.  Use as:

```python
from rest_tools.client import RestClient

api = RestClient('http://my.site.here/api', token='XXXX')
ret = await api.request('GET', '/fruits/apple')
ret = await api.request('POST', '/fruits', {'name': 'banana'})
```

There are several variations of the client for OAuth2/OpenID support:

* [`OpenIDRestClient`](rest_tools/client/openid_client.py#L19) : A child of
  `RestClient` that supports OAuth2 token refresh using the OpenID Connect
  Discovery protocol for an authentication server.

* [`ClientCredentialsAuth`](rest_tools/client/client_credentials.py#L11) : Uses
  `OpenIDRestClient` in combination with OAuth2 client credentials (client ID
  and secret) for service-based auth. Use this for long-lived services that
  need to perform REST API calls.

* [`DeviceGrantAuth`](rest_tools/client/device_client.py#L125) /
  [`SavedDeviceGrantAuth`](rest_tools/client/device_client.py#L162) : Uses
  `OpenIDRestClient` to perform a "device" login for a user. Use this for
  user-based terminal applications that need to perform REST API calls.
  The `SavedDeviceGrantAuth` can save the refresh token to disk, allowing
  repeated application sessions without having to log in again.

## Server

A REST API server exists under `rest_tools.server`. Use as:

```python
import asyncio
from rest_tools.server import RestServer, RestHandler

class Fruits(RestHandler):
    def post(self):
        # handle a new fruit
        self.write({})

server = RestServer()
server.add_route('/fruits', Fruits)
server.startup(address='my.site.here', port=8080)
asyncio.get_event_loop().run_forever()
```

The server uses [Tornado](https://tornado.readthedocs.io) to handle HTTP
connections. It is recommended to use Apache or Nginx as a front-facing proxy,
to handle TLS sessions and non-standard HTTP requests in production.

### Handling Arguments Server-side

`server.ArgumentHandler` is a robust wrapper around `argparse.ArgumentParser`, extended for use in handling REST arguments, both query arguments and JSON-encoded body arguments. The intended design of this class is to follow the `argparse` pattern as closely as possible.


```python
from rest_tools.server import RestHandler, ArgumentHandler, ArgumentSource

class Fruits(RestHandler):

    def get(self):
        argo = ArgumentHandler(ArgumentSource.QUERY_ARGUMENTS, self)

        argo.add_argument('name', type=str)  # de-facto required
        argo.add_argument('alias', dest='other_names', type=str, nargs='*', default=[])  # list

        argo.add_argument('is-citrus', type=bool, default=False)
        argo.add_argument('amount', type=float, required=True)

        args = argo.parse_args()

        fruit = get_fruit(args.name, args.other_names, args.is_citrus, args.amount)

        ...

    def post(self):
        argo = ArgumentHandler(ArgumentSource.JSON_BODY_ARGUMENTS, self)

        argo.add_argument('name', type=str)  # de-facto required
        argo.add_argument('other-names', type=list, default=[])

        argo.add_argument('supply', type=dict, required=True)

        def _origin(val):
            try:
                return {'USA': 'United States of America', 'MEX': 'Mexico'}[val]
            except KeyError:
                # raise a ValueError or TypeError to propagate a 400 Error
                raise ValueError('Invalid origin')

        argo.add_argument('country_code', dest='origin', type=_origin, required=True)

        args = argo.parse_args()

        add_to_basket(args.name, args.other_names, args.supply, args.origin)

        ...

```

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/WIPACrepo/rest-tools",
    "name": "wipac-rest-tools",
    "maintainer": null,
    "docs_url": null,
    "requires_python": "<3.13,>=3.8",
    "maintainer_email": null,
    "keywords": "python, REST, tools, utilities, OpenTelemetry, tracing, telemetry, WIPAC, IceCube",
    "author": "WIPAC Developers",
    "author_email": "developers@icecube.wisc.edu",
    "download_url": "https://files.pythonhosted.org/packages/53/af/d61b5f3cb9e4f5ef984ad472f6c0fe8c1f8107b5af82017213b69992edd7/wipac-rest-tools-1.7.3.tar.gz",
    "platform": null,
    "description": "<!--- Top of README Badges (automated) --->\n[![PyPI](https://img.shields.io/pypi/v/wipac-rest-tools)](https://pypi.org/project/wipac-rest-tools/) [![GitHub release (latest by date including pre-releases)](https://img.shields.io/github/v/release/WIPACrepo/rest-tools?include_prereleases)](https://github.com/WIPACrepo/rest-tools/) [![PyPI - License](https://img.shields.io/pypi/l/wipac-rest-tools)](https://github.com/WIPACrepo/rest-tools/blob/master/LICENSE) [![Lines of code](https://img.shields.io/tokei/lines/github/WIPACrepo/rest-tools)](https://github.com/WIPACrepo/rest-tools/) [![GitHub issues](https://img.shields.io/github/issues/WIPACrepo/rest-tools)](https://github.com/WIPACrepo/rest-tools/issues?q=is%3Aissue+sort%3Aupdated-desc+is%3Aopen) [![GitHub pull requests](https://img.shields.io/github/issues-pr/WIPACrepo/rest-tools)](https://github.com/WIPACrepo/rest-tools/pulls?q=is%3Apr+sort%3Aupdated-desc+is%3Aopen) \n<!--- End of README Badges (automated) --->\n# rest-tools\n\nThis project contains REST tools in python, as common code for multiple other\nprojects under https://github.com/WIPACrepo.\n\nAll code uses python [asyncio](https://docs.python.org/3/library/asyncio.html),\nso is fully asyncronous.\n\nNote that both the client and server assume starting the asyncio loop\nhappens elsewhere - they do not start the loop themselves.\n\n## Client\n\nA REST API client exists under `rest_tools.client`.  Use as:\n\n```python\nfrom rest_tools.client import RestClient\n\napi = RestClient('http://my.site.here/api', token='XXXX')\nret = await api.request('GET', '/fruits/apple')\nret = await api.request('POST', '/fruits', {'name': 'banana'})\n```\n\nThere are several variations of the client for OAuth2/OpenID support:\n\n* [`OpenIDRestClient`](rest_tools/client/openid_client.py#L19) : A child of\n  `RestClient` that supports OAuth2 token refresh using the OpenID Connect\n  Discovery protocol for an authentication server.\n\n* [`ClientCredentialsAuth`](rest_tools/client/client_credentials.py#L11) : Uses\n  `OpenIDRestClient` in combination with OAuth2 client credentials (client ID\n  and secret) for service-based auth. Use this for long-lived services that\n  need to perform REST API calls.\n\n* [`DeviceGrantAuth`](rest_tools/client/device_client.py#L125) /\n  [`SavedDeviceGrantAuth`](rest_tools/client/device_client.py#L162) : Uses\n  `OpenIDRestClient` to perform a \"device\" login for a user. Use this for\n  user-based terminal applications that need to perform REST API calls.\n  The `SavedDeviceGrantAuth` can save the refresh token to disk, allowing\n  repeated application sessions without having to log in again.\n\n## Server\n\nA REST API server exists under `rest_tools.server`. Use as:\n\n```python\nimport asyncio\nfrom rest_tools.server import RestServer, RestHandler\n\nclass Fruits(RestHandler):\n    def post(self):\n        # handle a new fruit\n        self.write({})\n\nserver = RestServer()\nserver.add_route('/fruits', Fruits)\nserver.startup(address='my.site.here', port=8080)\nasyncio.get_event_loop().run_forever()\n```\n\nThe server uses [Tornado](https://tornado.readthedocs.io) to handle HTTP\nconnections. It is recommended to use Apache or Nginx as a front-facing proxy,\nto handle TLS sessions and non-standard HTTP requests in production.\n\n### Handling Arguments Server-side\n\n`server.ArgumentHandler` is a robust wrapper around `argparse.ArgumentParser`, extended for use in handling REST arguments, both query arguments and JSON-encoded body arguments. The intended design of this class is to follow the `argparse` pattern as closely as possible.\n\n\n```python\nfrom rest_tools.server import RestHandler, ArgumentHandler, ArgumentSource\n\nclass Fruits(RestHandler):\n\n    def get(self):\n        argo = ArgumentHandler(ArgumentSource.QUERY_ARGUMENTS, self)\n\n        argo.add_argument('name', type=str)  # de-facto required\n        argo.add_argument('alias', dest='other_names', type=str, nargs='*', default=[])  # list\n\n        argo.add_argument('is-citrus', type=bool, default=False)\n        argo.add_argument('amount', type=float, required=True)\n\n        args = argo.parse_args()\n\n        fruit = get_fruit(args.name, args.other_names, args.is_citrus, args.amount)\n\n        ...\n\n    def post(self):\n        argo = ArgumentHandler(ArgumentSource.JSON_BODY_ARGUMENTS, self)\n\n        argo.add_argument('name', type=str)  # de-facto required\n        argo.add_argument('other-names', type=list, default=[])\n\n        argo.add_argument('supply', type=dict, required=True)\n\n        def _origin(val):\n            try:\n                return {'USA': 'United States of America', 'MEX': 'Mexico'}[val]\n            except KeyError:\n                # raise a ValueError or TypeError to propagate a 400 Error\n                raise ValueError('Invalid origin')\n\n        argo.add_argument('country_code', dest='origin', type=_origin, required=True)\n\n        args = argo.parse_args()\n\n        add_to_basket(args.name, args.other_names, args.supply, args.origin)\n\n        ...\n\n```\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "REST tools in python - common code for client and server",
    "version": "1.7.3",
    "project_urls": {
        "Download": "https://pypi.org/project/wipac-rest-tools/",
        "Homepage": "https://github.com/WIPACrepo/rest-tools",
        "Source": "https://github.com/WIPACrepo/rest-tools",
        "Tracker": "https://github.com/WIPACrepo/rest-tools/issues"
    },
    "split_keywords": [
        "python",
        " rest",
        " tools",
        " utilities",
        " opentelemetry",
        " tracing",
        " telemetry",
        " wipac",
        " icecube"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "45cab399432ea43d991ea78987ca9eb521a5082cb7546ac37eb2f788f601e98d",
                "md5": "430d4029dfcb1edb3ffd825ec91bdd31",
                "sha256": "ca2c8b2fae08605936db050d1ec127a655ae0d379b96782dc21a256797d54c5d"
            },
            "downloads": -1,
            "filename": "wipac_rest_tools-1.7.3-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "430d4029dfcb1edb3ffd825ec91bdd31",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": "<3.13,>=3.8",
            "size": 37471,
            "upload_time": "2024-05-01T17:53:11",
            "upload_time_iso_8601": "2024-05-01T17:53:11.112585Z",
            "url": "https://files.pythonhosted.org/packages/45/ca/b399432ea43d991ea78987ca9eb521a5082cb7546ac37eb2f788f601e98d/wipac_rest_tools-1.7.3-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "53afd61b5f3cb9e4f5ef984ad472f6c0fe8c1f8107b5af82017213b69992edd7",
                "md5": "487cb894268cb2c1375c165a62ad1f4a",
                "sha256": "28d39968bc48116638c23d5876b60a57f37381d2399667e7d5a871fb91ea3553"
            },
            "downloads": -1,
            "filename": "wipac-rest-tools-1.7.3.tar.gz",
            "has_sig": false,
            "md5_digest": "487cb894268cb2c1375c165a62ad1f4a",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": "<3.13,>=3.8",
            "size": 32343,
            "upload_time": "2024-05-01T17:53:14",
            "upload_time_iso_8601": "2024-05-01T17:53:14.302301Z",
            "url": "https://files.pythonhosted.org/packages/53/af/d61b5f3cb9e4f5ef984ad472f6c0fe8c1f8107b5af82017213b69992edd7/wipac-rest-tools-1.7.3.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-05-01 17:53:14",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "WIPACrepo",
    "github_project": "rest-tools",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "wipac-rest-tools"
}
        
Elapsed time: 0.24536s