You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
61 lines
2.6 KiB
Markdown
61 lines
2.6 KiB
Markdown
# API design decisions
|
|
|
|
Generated API is modified from what `openapi-generator` does by default.
|
|
Changes are mostly focused on better user experience - including better
|
|
usage patterns and simpler/faster ways to achieve results.
|
|
|
|
## Changes
|
|
|
|
- Added type annotations for return types and class members
|
|
This change required us to implement a custom post-processing script,
|
|
which converts generated types into correct type annotations. The types
|
|
generated by default are supposed to work with the API implementation
|
|
(parameter validation and parsing), but they are not applicable as
|
|
type annotations (they have incorrect syntax). Custom post-processing
|
|
allowed us to make these types correct type annotations.
|
|
Other possible solutions:
|
|
- There is a `python-experimental` API generator, which may solve
|
|
some issues, but it is unstable and requires python 3.9. Our API
|
|
works with 3.7, which is the lowest supported version now.
|
|
- Custom templates - partially works, but only in limited cases
|
|
(model fields). It's very hard to maintain the template code and
|
|
logic for this. Only `if` checks and `for` loops are available in
|
|
mustache templates, which is not enough for annotation generation.
|
|
|
|
- Separate APIs are embedded into the general `APIClient` class
|
|
Now we have:
|
|
```python
|
|
with ApiClient(config) as api_client:
|
|
result1 = api_client.foo_api.operation1()
|
|
result2 = api_client.bar_api.operation2()
|
|
```
|
|
|
|
This showed to be more convenient than default:
|
|
```python
|
|
with ApiClient(config) as api_client:
|
|
foo_api = FooApi(api_client)
|
|
result1 = foo_api.operation1()
|
|
result2 = foo_api.operation2()
|
|
|
|
bar_api = BarApi(api_client)
|
|
result3 = bar_api.operation3()
|
|
result4 = bar_api.operation4()
|
|
```
|
|
|
|
This also required custom post-processing. Operation Ids are
|
|
[supposed to be unique](https://swagger.io/specification/#operation-object)
|
|
in the OpenAPI / Swagger specification. Therefore, we can't generate such
|
|
schema on the server, nor we can't expect it to be supported in the
|
|
API generator.
|
|
|
|
- Operations have IDs like `<api>/<method>_<object>`
|
|
This also showed to be more readable and more natural than DRF-spectacular's
|
|
default `<api>/<object>_<method>`.
|
|
|
|
- Server operations have different types for input and output values
|
|
While it can be expected that an endopint with POST/PUT methods available
|
|
(like `create` or `partial_update`) has the same type for input and output
|
|
(because it looks natural), it also leads to the situation, in which there
|
|
are lots of read-/write-only fields, and it becomes hard for understanding.
|
|
This clear type separation is supposed to make it simpler for users.
|