# 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.
