apple / apple/swift-openapi-generator

Support additional strongly-typed scalars

Open
#375 13 comments 0 reactions 0 assignees View on GitHub
kind/feature status/needs-design
Dominant language
Swift
Stars
2k
Forks
182
Avg merge
13h 28m
Merged PRs (30d)
5

Description

Hello,

I was wondering if OpenAPI or the OpenAPI generator could define new scalar types.

New scalar types help disambiguating scalar values such as integers or strings by making them strongly typed: this is a user id, this is an ISO-8601 date, this is a number of seconds, this is an amount of cents. With strong typing, mixing apples and oranges is impossible.

OpenAPI has something that looks pretty much like this:

```yml
components:
schemas:
# A custom string scalar:
URL:
type: string

PhoneNumber:
type: object
properties:
localized_description:
type: string
# Not a string, but a URL:
url:
$ref: '#/components/schemas/URL'
required:
- localized_description
- url
```

But OpenAPI Generator imports them as their raw Swift type. For example:

```swift
// Generated
public enum Components {
public enum Schemas {
/// - Remark: Generated from `#/components/schemas/URL`.
public typealias URL = Swift.String
}
}
```

Somehow I was expecting `Components.Schemas.URL` to be generated as a `RawRepresentable` type, as below. I thought that the definition of `#/components/schemas/URL` was a sufficient hint for the desire of a custom type:

```swift
// My expectation
public enum Components {
public enum Schemas {
/// - Remark: Generated from `#/components/schemas/URL`.
public struct URL: Codable, Hashable, Sendable, RawRepresentable {
public var rawValue: String

public init(rawValue: String) {
self.rawValue = rawValue
}

public init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
try self.init(rawValue: container.decode(String.self))
}

public func encode(to encoder: any Encoder) throws {
var container = encoder.singleValueContainer()
try container.encode(rawValue)
}
}
}
}
```

I understand that OpenAPI supports a lot of features, such as string formats, that can turn a simple feature into a very complex beast.

I also understand that not everybody has a real or strong need for strongly-types scalars. They could *annoy* some users ("All those raw values 🙄").

My previous experience with strongly-types scalars was the Swift GraphQL library Apollo: [Custom Scalars](https://www.apollographql.com/docs/ios/custom-scalars/). By default, it imports custom scalars as their raw Swift representation (so the `URL` above with also be a typealias to `Swift.String`). But it allows the developer to provide a custom implementation. I was able to replace all those raw `String` and `Int` with [tagged values](https://github.com/pointfreeco/swift-tagged), with much happiness.

In the end, I wonder what is the opinion of the library maintainers on such a topic?

Contributor guide

Open the contributing guide

Research direction

Start by reviewing how the generator currently turns the issue's OpenAPI scalar schemas into Swift typealiases such as Components.Schemas.URL. Compare that behavior with the proposed RawRepresentable shape and the Apollo custom-scalars approach, then define the configuration and compatibility decisions needed before implementation. Done should include an agreed design and corresponding generator coverage for custom scalar types.

Written by the indexing model from the issue text.

Assessment

Tech stack
openapi, swift
Domain
api
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.