Skip to content

feat(client): add support for passing in a httpx client #123

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 28 additions & 25 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
# Finch Python API Library
# Finch Python API library

[![PyPI version](https://img.shields.io/pypi/v/finch-api.svg)](https://pypi.org/project/finch-api/)

The Finch Python library provides convenient access to the Finch REST API from any Python 3.7+
application. It includes type definitions for all request params and response fields,
application. The library includes type definitions for all request params and response fields,
and offers both synchronous and asynchronous clients powered by [httpx](https://github.com/encode/httpx).

## Documentation

The API documentation can be found [here](https://developer.tryfinch.com/).
The API documentation can be found at [https://developer.tryfinch.com/](https://developer.tryfinch.com/).

## Installation

Expand All @@ -34,7 +34,7 @@ directory = page.individuals[0]
print(directory.first_name)
```

## Async Usage
## Async usage

Simply import `AsyncFinch` instead of `Finch` and use `await` with each API call:

Expand All @@ -58,11 +58,11 @@ asyncio.run(main())

Functionality between the synchronous and asynchronous clients is otherwise identical.

## Using Types
## Using types

Nested request parameters are [TypedDicts](https://docs.python.org/3/library/typing.html#typing.TypedDict). Responses are [Pydantic models](https://docs.pydantic.dev), which provide helper methods for things like serializing back into json ([v1](https://docs.pydantic.dev/1.10/usage/models/), [v2](https://docs.pydantic.dev/latest/usage/serialization/)). To get a dictionary, you can call `dict(model)`.
Nested request parameters are [TypedDicts](https://docs.python.org/3/library/typing.html#typing.TypedDict). Responses are [Pydantic models](https://docs.pydantic.dev), which provide helper methods for things like serializing back into JSON ([v1](https://docs.pydantic.dev/1.10/usage/models/), [v2](https://docs.pydantic.dev/latest/usage/serialization/)). To get a dictionary, call `dict(model)`.

This helps provide autocomplete and documentation within your editor. If you would like to see type errors in VS Code to help catch bugs earlier, set `python.analysis.typeCheckingMode` to `"basic"`.
Typed requests and responses provide autocomplete and documentation within your editor. If you would like to see type errors in VS Code to help catch bugs earlier, set `python.analysis.typeCheckingMode` to `basic`.

## Pagination

Expand Down Expand Up @@ -169,10 +169,10 @@ async def handler(request: Request):

## Handling errors

When the library is unable to connect to the API (e.g., due to network connection problems or a timeout), a subclass of `finch.APIConnectionError` is raised.
When the library is unable to connect to the API (for example, due to network connection problems or a timeout), a subclass of `finch.APIConnectionError` is raised.

When the API returns a non-success status code (i.e., 4xx or 5xx
response), a subclass of `finch.APIStatusError` will be raised, containing `status_code` and `response` properties.
When the API returns a non-success status code (that is, 4xx or 5xx
response), a subclass of `finch.APIStatusError` is raised, containing `status_code` and `response` properties.

All errors inherit from `finch.APIError`.

Expand Down Expand Up @@ -210,11 +210,11 @@ Error codes are as followed:

### Retries

Certain errors will be automatically retried 2 times by default, with a short exponential backoff.
Certain errors are automatically retried 2 times by default, with a short exponential backoff.
Connection errors (for example, due to a network connectivity problem), 408 Request Timeout, 409 Conflict,
429 Rate Limit, and >=500 Internal errors will all be retried by default.
429 Rate Limit, and >=500 Internal errors are all retried by default.

You can use the `max_retries` option to configure or disable this:
You can use the `max_retries` option to configure or disable retry settings:

```python
from finch import Finch
Expand All @@ -231,8 +231,8 @@ client.with_options(max_retries=5).hris.directory.list_individuals()

### Timeouts

Requests time out after 1 minute by default. You can configure this with a `timeout` option,
which accepts a float or an [`httpx.Timeout`](https://www.python-httpx.org/advanced/#fine-tuning-the-configuration):
By default requests time out after 1 minute. You can configure this with a `timeout` option,
which accepts a float or an [`httpx.Timeout`](https://www.python-httpx.org/advanced/#fine-tuning-the-configuration) object:

```python
from finch import Finch
Expand All @@ -254,7 +254,7 @@ client.with_options(timeout=5 * 1000).hris.directory.list_individuals()

On timeout, an `APITimeoutError` is thrown.

Note that requests which time out will be [retried twice by default](#retries).
Note that requests that time out are [retried twice by default](#retries).

## Default Headers

Expand All @@ -276,7 +276,7 @@ client = Finch(

### How to tell whether `None` means `null` or missing

In an API response, a field may be explicitly null, or missing entirely; in either case, its value is `None` in this library. You can differentiate the two cases with `.model_fields_set`:
In an API response, a field may be explicitly `null`, or missing entirely; in either case, its value is `None` in this library. You can differentiate the two cases with `.model_fields_set`:

```py
if response.my_field is None:
Expand All @@ -286,27 +286,30 @@ if response.my_field is None:
print('Got json like {"my_field": null}.')
```

### Configuring custom URLs, proxies, and transports
### Configuring the HTTP client

You can configure the following keyword arguments when instantiating the client:
You can directly override the [httpx client](https://www.python-httpx.org/api/#client) to customize it for your use case, including:

- Support for proxies
- Custom transports
- Additional [advanced](https://www.python-httpx.org/advanced/#client-instances) functionality

```python
import httpx
from finch import Finch

client = Finch(
# Use a custom base URL
base_url="http://my.test.server.example.com:8083",
proxies="http://my.test.proxy.example.com",
transport=httpx.HTTPTransport(local_address="0.0.0.0"),
http_client=httpx.Client(
proxies="http://my.test.proxy.example.com",
transport=httpx.HTTPTransport(local_address="0.0.0.0"),
),
)
```

See the httpx documentation for information about the [`proxies`](https://www.python-httpx.org/advanced/#http-proxying) and [`transport`](https://www.python-httpx.org/advanced/#custom-transports) keyword arguments.

### Managing HTTP resources

By default we will close the underlying HTTP connections whenever the client is [garbage collected](https://docs.python.org/3/reference/datamodel.html#object.__del__) is called but you can also manually close the client using the `.close()` method if desired, or with a context manager that closes when exiting.
By default the library closes underlying HTTP connections whenever the client is [garbage collected](https://docs.python.org/3/reference/datamodel.html#object.__del__). You can manually close the client using the `.close()` method if desired, or with a context manager that closes when exiting.

## Versioning

Expand Down
Loading