# restful-client-lite [![Build Status](https://travis-ci.com/huandzh/restful-client-lite.svg?branch=master)](https://travis-ci.com/huandzh/restful-client-lite)

A lite client for RESTFul APIs with limited features.

It provides:

* `restful_client_lite.APIClient`: client for [eve](https://docs.python-eve.org) token-auth apps
* `restful_client_lite.contrib.AliyunApiGatewayClient`: client for apis generated by [aliyun DataService](https://help.aliyun.com/document_detail/73295.html?spm=a2c4g.11186623.6.838.74b233b40qZs2W) (only `GET` is supported)
* `restful_client_lite.contrib.WangduoyunApiClient`: client for Wangduoyun apis by [WangDuoYun](https://docs.wangduoyun.com/develop/overview/aboutus.html)

WIP.(not stable before v0.1.0)

## Installation

### Lastest release ![PyPI](https://img.shields.io/pypi/v/restful_client_lite)

pipenv:

```shell
pipenv install restful_client_lite
```

pip:

```shell
pip install restful_client_lite
```
### Dev

pipenv:

```shell
pipenv install -e git+https://github.com/huandzh/restful-client-lite#egg=restful-client-lite
```

pip:

```shell
pip install -e git+https://github.com/huandzh/restful-client-lite#egg=restful-client-lite
```

## Usage

Assume that we have a restful api requiring `Authorization:<token>` in the header and using etag to control writes.

Create an API client:

```python
from restful_client_lite import APIClient
api = APIClient("<api_root>", {"token": "<token>"})
```

Get from url:

```python
res_get = api.get("<url>")
```

Post to url:

```python
res_post = api.post("<url>", data={"<key>": "<value>"})
```

Patch url:

```python
res_patch = api.patch("<url>", "<etag>", data={"<key>": "<value>"})
```

Patch url (fetch etag automatically in advance):

```python
res_patch = api.patch_auto_etag("<url>", data={"<key>": "<value>"})
```

Delete url:

```python
res_delete = api.delete("<url>", "<etag>")
```

Delete url (fetch etag automatically in advance):

```python
res_delete = api.delete_auto_etag("<url>")
```

Subclass `APIClient` to create custom api client:

```python
def sign(url):
    """some function return signature"""
    ...
    return <signed url>

class CustomAPIClient(APIClient):
    """custom api client"""

    def auth_headers(self, f: Callable) -> Callable:
        """custom auth headers"""
        @wraps(f)
        def wrapper(*args, **kwargs):
            headers = kwargs.get("headers", {}).copy()
            url = args[0]
            headers.update({"Signature": sign(url)})
            kwargs["headers"] = headers
            return f(*args, **kwargs)
```

## 3rd-party APIs

### aliyun api gateway

`AliyunApiGatewayClient` :

* support `GET` from aliyun-api-gateway apis (apis may generated by DataService)
* handle authorization headers
* **doesn't** sort url params

```python
from restful_client_lite.contrib.aliyun import AliyunApiGatewayClient
api = AliyunApiGatewayClient(
    '<api_root>',
    {"app_id": '<app_id>',
    "app_secret": '<app_secret>'})
# make sure params in <url> are sorted
res = api.get('<url>')
```

### wangduoyun api

`WangduoyunApiClient`:

* support account apis
* support graphql apis

```python
# client adds required authorization data for POST
api = WangduoyunApiClient(
    "<api_root>",
    {"user_key": "<user_key>",
    "user_secret": "<user_secret>"})
res = api.post("<url>")
```

```python
# client provides `get_sign` to get authorization params
api = WangduoyunApiClient(
    "<api_root>",
    {"user_key": "<user_key>",
    "user_secret": "<user_secret>"})
sign, timestamp = api.get_sign()
url = "?user_key={user_key}&timestamp={timestamp}&sign={sign}&source_id={source_id}&query={query}".format(
    user_key=api.auth['user_key'],
    timestamp=timestamp,
    sign=sign,
    source_id="<source_id>",
    query="<query>")
res = api.get(url)
```
