-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Paul Hallett
committed
Jul 25, 2023
1 parent
f51f89b
commit 89d4584
Showing
23 changed files
with
881 additions
and
150 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,4 +7,5 @@ env.ini | |
__pycache__ | ||
.DS_Store | ||
test_output/ | ||
dist/ | ||
dist/ | ||
site/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,17 +1,26 @@ | ||
# Changelog | ||
# Change log | ||
|
||
## 0.1.0 | ||
## 0.3.0 | ||
|
||
- Initial version | ||
- Mostly works with a simple FastAPI generated spec (3.0.2) | ||
- Works with Twilio's spec (see example_openapi_specs/ directory) (3.0.1) | ||
- Almost works with stripes | ||
- Now generates a `MANIFEST` file with information about the build versions | ||
- Added a `constants.py` file to the output if one does not exist yet, which can be used to store values that you do not want to change between subsequent re-generations of the clientele client, such as the API base url. | ||
- Authentication patterns now use `constants.py` for constants values. | ||
- Removed `ipython` from package dependencies and moved to dev dependencies. | ||
- Documentation! [https://beckett-software.github.io/clientele/](https://beckett-software.github.io/clientele/) | ||
|
||
### 0.2.0 | ||
## 0.2.0 | ||
|
||
- Improved CLI output | ||
- Code organisation is now sensible and not just one giant file | ||
- Now supports an openapi spec generated from a dotnet project (`Microsoft.OpenApi.Models`) | ||
- async client support fully working | ||
- HTTP Bearer support | ||
- HTTP Basic support | ||
|
||
|
||
## 0.1.0 | ||
|
||
- Initial version | ||
- Mostly works with a simple FastAPI generated spec (3.0.2) | ||
- Works with Twilio's spec (see example_openapi_specs/ directory) (3.0.1) | ||
- Almost works with stripes |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
# Change log | ||
|
||
## 0.3.0 | ||
|
||
- Now generates a `MANIFEST` file with information about the build versions | ||
- Added a `constants.py` file to the output if one does not exist yet, which can be used to store values that you do not want to change between subsequent re-generations of the clientele client, such as the API base url. | ||
- Authentication patterns now use `constants.py` for constants values. | ||
- Removed `ipython` from package dependencies and moved to dev dependencies. | ||
- Documentation! [https://beckett-software.github.io/clientele/](https://beckett-software.github.io/clientele/) | ||
|
||
## 0.2.0 | ||
|
||
- Improved CLI output | ||
- Code organisation is now sensible and not just one giant file | ||
- Now supports an openapi spec generated from a dotnet project (`Microsoft.OpenApi.Models`) | ||
- async client support fully working | ||
- HTTP Bearer support | ||
- HTTP Basic support | ||
|
||
|
||
## 0.1.0 | ||
|
||
- Initial version | ||
- Mostly works with a simple FastAPI generated spec (3.0.2) | ||
- Works with Twilio's spec (see example_openapi_specs/ directory) (3.0.1) | ||
- Almost works with stripes |
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
# 💱 Compatability | ||
|
||
When we were building Clientele, we discovered that, despite a fantastic [specification](https://www.openapis.org/), OpenAPI has a lot of poor implementations. | ||
|
||
As pythonistas, we started with the auto-generated OpenAPI schemas provided by [FastAPI](https://fastapi.tiangolo.com/), and then we branched out to large APIs like [Twilio](https://www.twilio.com/docs/openapi) to test what we built. | ||
|
||
Despite the effort, we still keep finding subtly different OpenAPI implementations. Because of this we cannot guarentee 100% compatability with an API, but we can give you a good indication of what we've tested. | ||
|
||
## Works well with | ||
|
||
Any bog-standard `3.0.x` implementation works very well. | ||
|
||
* [FastAPI](https://fastapi.tiangolo.com/tutorial/first-steps/?h=openapi#what-is-openapi-for)'s OpenAPI schema is very well supported. | ||
* [Microsoft's OpenAPI spec](https://learn.microsoft.com/en-us/azure/api-management/import-api-from-oas?tabs=portal) has also been battle tested on an internal project, and works well. | ||
|
||
|
||
## Does not work | ||
|
||
We do not support `2.x` aka "Swagger" - this format is quite different and deprecated. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,151 @@ | ||
# 🪄 Client example | ||
|
||
Let's build an API Client using clientele and an example OpenAPI schema. | ||
|
||
Our [GitHub](https://github.com/beckett-software/clientele/tree/main/example_openapi_specs) has a bunch of schemas that are proven to work with clientele, so let's use one of those! | ||
|
||
## Generate the client | ||
|
||
Very simply: | ||
|
||
```sh | ||
clientele generate -u https://raw.githubusercontent.com/beckett-software/clientele/main/example_openapi_specs/simple.json -o my_client/ | ||
``` | ||
|
||
The `-u` parameter expects a URL, you can provide a path to a file with `-f` instead if you download the file. | ||
|
||
The `-o` parameter is the output directory of the generated client. | ||
|
||
Run it now and you will see this output: | ||
|
||
```sh | ||
my_client/ | ||
__init__.py | ||
client.py | ||
constants.py | ||
http.py | ||
MANIFEST | ||
schemas.py | ||
``` | ||
|
||
## Client directory | ||
|
||
Let's go over each file and talk about what it does | ||
|
||
### client.py | ||
|
||
This file provides all the client functions. | ||
|
||
```py title="my_client/client.py" linenums="1" | ||
import typing # noqa | ||
from . import schemas # noqa | ||
from . import http # noqa | ||
|
||
|
||
def HealthCheckHealthCheckGet() -> schemas.HealthCheckResponse: | ||
response = http.get("/health-check") | ||
return http.handle_response(HealthCheckHealthCheckGet, response) | ||
|
||
|
||
def TestInputTestInputPost( | ||
data: schemas.TestInputData, | ||
) -> typing.Union[schemas.HTTPValidationError, schemas.TestInputResponse]: | ||
response = http.post("/test-input", data=data and data.model_dump()) | ||
return http.handle_response(TestInputTestInputPost, response) | ||
``` | ||
|
||
We can see one of the functions here, `HealthCheckHealthCheckGet`, is for a straight-forward HTTP GET request without any input arguments, and it returns a schema object. If the endpoint has url parameters or query parameters, they will appear as input arguments to the function. | ||
|
||
```py | ||
def HealthCheckHealthCheckGet() -> schemas.HealthCheckResponse: | ||
response = http.get("/health-check") | ||
return http.handle_response(HealthCheckHealthCheckGet, response) | ||
``` | ||
|
||
Here is how you might use it: | ||
|
||
```py | ||
from my_client import client | ||
|
||
client.HealthCheckHealthCheckGet() | ||
>>> HealthCheckResponse(status='ok') | ||
``` | ||
|
||
A more complex example is shown just below - `TestInputTestInputPost`, this is for an HTTP POST method, and it requires an input property called `data` that is an instance of a schema, and returns a union of responses. If the endpoint has url parameters or query parameters, they will appear as input arguments to the function alongside the `data` argument. | ||
|
||
```py | ||
def TestInputTestInputPost( | ||
data: schemas.TestInputData, | ||
) -> typing.Union[schemas.HTTPValidationError, schemas.TestInputResponse]: | ||
response = http.post("/test-input", data=data and data.model_dump()) | ||
return http.handle_response(TestInputTestInputPost, response) | ||
``` | ||
|
||
Here is how you might use it: | ||
|
||
```py | ||
from my_client import client, schemas | ||
|
||
data = schemas.TestInputData(my_title="Hello, world") | ||
client.TestInputTestInputPost(data=data) | ||
>>> TestInputResponse(title='Hello, world') | ||
``` | ||
|
||
Because we're using Pydantic to manage the input data, we get a strongly-typed interface for us. | ||
|
||
### schemas.py | ||
|
||
This file has all the possible schemas, request and response, for the API. | ||
|
||
They are all subclassed from pydantic's `BaseModel`. Here are a few examples: | ||
|
||
```py title="my_client/schemas.py" linenums="1" | ||
import typing # noqa | ||
from pydantic import BaseModel # noqa | ||
from enum import Enum # noqa | ||
|
||
|
||
class HTTPValidationError(BaseModel): | ||
detail: typing.List[typing.Any] | ||
|
||
|
||
class HealthCheckResponse(BaseModel): | ||
status: str | ||
|
||
|
||
class TestInputData(BaseModel): | ||
my_title: str | ||
|
||
|
||
class TestInputResponse(BaseModel): | ||
title: str | ||
|
||
|
||
class ValidationError(BaseModel): | ||
loc: typing.List[typing.Any] | ||
msg: str | ||
type: str | ||
|
||
``` | ||
|
||
### http.py | ||
|
||
This file manages the HTTP layer of the client. | ||
|
||
You should never need to touch the code here, but feel free to have a browse. | ||
|
||
This file will have either a sync, or an async instance of a client from `httpx`. | ||
|
||
It also manages the coersion of response bodies into schema objects. | ||
|
||
### constants.py | ||
|
||
This manages all the configuration your client might need. | ||
|
||
This file is only ever generated once, and will never be overwritten (unless you delete it yourself). | ||
|
||
You can modify the contents of the functions in this file to provide things like the base url and authentication keys for your client. | ||
|
||
### MANIFEST | ||
|
||
The `MANIFEST` file provides some information on how the client was generated. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
# ⚜️ Clientele | ||
|
||
# Typed API Clients from OpenAPI specs | ||
|
||
![clientele_logo](https://github.com/beckett-software/clientele/blob/main/docs/clientele.jpeg?raw=true) | ||
|
||
Clientele lets you generate fully-typed, functional, API Clients from OpenAPI specs. | ||
|
||
It uses modern tools to be blazing fast and type safe. | ||
|
||
Plus - there is no complex boilerplate and the generated code is very small. | ||
|
||
## Features | ||
|
||
* Fully typed API Client using Pydantic. | ||
* Minimalist and easy to use - the generated code is designed for readability. | ||
* Choose either sync or async - we support both, and you can switch between them easily. | ||
* Supports authentication (curently only HTTP Bearer and HTTP Basic auth). | ||
* Written entirely in Python - no need to install other languages to use OpenAPI. | ||
* The client footprint is minimal - it only requires `httpx` and `pydantic`. | ||
* Supports your own configuration - we provide an entry point that will never be overwritten. | ||
|
||
We're built on: | ||
|
||
* [Pydantic 2.0](https://docs.pydantic.dev/latest/) | ||
* [httpx](https://www.python-httpx.org/) | ||
* [openapi-core](https://openapi-core.readthedocs.io/en/latest/) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
# 🏗️ Install | ||
|
||
We recommend using [poetry](https://python-poetry.org/) to manage your python packages. | ||
|
||
```sh | ||
poetry add clientele | ||
``` | ||
|
||
We also work with [pip](https://pip.pypa.io/en/stable/) | ||
|
||
```sh | ||
pip install clientele | ||
``` |
Oops, something went wrong.