Skip to content

SOAR-0014: TypeOverrides #774

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

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,4 @@ If you have any questions, tag [Honza Dvorsky](https://github.com/czechboy0) or
- <doc:SOAR-0011>
- <doc:SOAR-0012>
- <doc:SOAR-0013>
- <doc:SOAR-0014>
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
# SOAR-0014: Support Type Overrides

Allow using user-defined types instead of generated ones

## Overview

- Proposal: SOAR-0014
- Author(s): [simonbility](https://github.com/simonbility)
- Status: **Awaiting Review**
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- Status: **Awaiting Review**
- Status: **Ready for Implementation**

- Issue: [apple/swift-openapi-generator#375](https://github.com/apple/swift-openapi-generator/issues/375)
- Implementation:
- [apple/swift-openapi-generator#764](https://github.com/apple/swift-openapi-generator/pull/764)
- Affected components:
- generator

### Introduction

The goal of this proposal is to allow users to specify custom types for generated. This will enable users to use their own types instead of the default generated ones, allowing for greater flexibility.

### Motivation

This proposal would enable more flexibility in the generated code.
Some usecases include:
- Using custom types that are already defined in the user's codebase or even coming from a third party library, instead of generating new ones.
- workaround missing support for `format` for strings
- Implement custom validation/encoding/decoding logic that cannot be expressed using the OpenAPI spec

This is intended as a "escape hatch" for use-cases that (currently) cannot be expressed.
Using this comes with the risk of user-provided types not being compliant with the original OpenAPI spec.


### Proposed solution

The proposed solution is to allow specifying typeOverrides using a new configuration option named `typeOverrides`.
This is only supported for schemas defined in the `components.schemas` section of a OpenAPI document.

### Example
A current limitiation is string formats are not directly supported by the generator. (for example, `uuid` is not supported)

With this proposal this can be worked around with with the following approach (This proposal does not preclude extending support for formats in the future):

Given schemas defined in the OpenAPI document like this:
```yaml
components:
schemas:
UUID:
type: string
format: uuid
```

Adding typeOverrides like this in the configuration

```diff
+ typeOverrides:
+ schemas:
+ UUID: Foundation.UUID
```

Will affect the generated code in the following way:
```diff
/// Types generated from the `#/components/schemas` section of the OpenAPI document.
package enum Schemas {
/// - Remark: Generated from `#/components/schemas/UUID`.
- package typealias Uuid = Swift.String
+ package typealias Uuid = Foundation.UUID
}
```

### Detailed design

In the configuration file a new `typeOverrides` option is supported.
It contains mapping from the original name (as defined in the OpenAPI document) to a override type name to use instead of the generated name.

The mapping is evaluated relative to `#/components/schemas`

So defining overrides like this:

```diff
typeOverrides:
schemas:
OriginalName: NewName
```

will replace the generated type for `#/components/schemas/OriginalName` with `NewName`.

Its in the users responsibility to ensure that the type is valid and available.
It must conform to `Codable`, `Hashable` and `Sendable`


### API stability

While this proposal does affect the generated code, it requires the user to explicitly opt-in to using the `typeOverrides` configuration option.

This is interpreted as a "strong enough" signal of the user to opt into this behaviour, to justify NOT introducing a feature-flag or considering this a breaking change.


### Future directions

The implementation could potentially be extended to support inline defined properties as well.
This could be done by supporting "Paths" instead of names in the mapping.

For example with the following schema.
```yaml
components:
schemas:
User:
properties:
id:
type: string
format: uuid
```

This configuration could be used to override the type of `id`:
```yaml
typeOverrides:
schemas:
'User/id': Foundation.UUID
```


### Alternatives considered
An alternative to the mapping defined in the configuration file is to use a vendor extension (for instance `x-swift-open-api-override-type`) in the OpenAPI document itself.

```yaml
...
components:
schemas:
UUID:
type: string
x-swift-open-api-override-type: Foundation.UUID
```

The current proposal using the configuration file was preferred because it does not rely on modifying the OpenAPI document itself, which is not always possible/straightforward when its provided by a third-party.