Skip to content
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

Generate enums for server variables #628

Closed
theoriginalbit opened this issue Sep 18, 2024 · 0 comments · Fixed by #618
Closed

Generate enums for server variables #628

theoriginalbit opened this issue Sep 18, 2024 · 0 comments · Fixed by #618
Assignees
Labels
kind/feature New feature. status/needs-design Needs further discussion and a concrete proposal.
Milestone

Comments

@theoriginalbit
Copy link
Contributor

Motivation

Recently in a project I was using a spec which defined variables similar to below

servers:
  - url: https://{environment}.example.com/api/{version}
    description: Example service deployment.
    variables:
      environment:
        description: Server environment.
        default: prod
        enum:
          - prod
          - staging
          - dev
      version:
        default: v1

The generated code to create the default server URL was easy enough being able to utilise the default variable

let serverURL = try Servers.server1()

But when I wanted to use a different variable I noticed that the parameter was generated as a string and it didn't expose the other allowed values that were defined in the OpenAPI document. It generated the following code:

/// Server URLs defined in the OpenAPI document.
internal enum Servers {
    ///
    /// - Parameters:
    ///   - environment:
    ///   - version:
    internal static func server1(
        environment: Swift.String = "prod",
        version: Swift.String = "v1"
    ) throws -> Foundation.URL {
        try Foundation.URL(
            validatingOpenAPIServerURL: "https://{environment}.example.com/api/{version}",
            variables: [
                .init(
                    name: "environment",
                    value: environment,
                    allowedValues: [
                        "prod",
                        "staging",
                        "dev"
                    ]
                ),
                .init(
                    name: "version",
                    value: version
                )
            ]
        )
    }
}

This meant usage needed to involve runtime checks whether the supplied variable was valid and if the OpenAPI document were to ever remove an option it could only be discovered at runtime.

let serverURL = try Servers.server1(environment: "stg") // might be a valid environment, might not

Looking into the OpenAPI spec for server templating and the implementation of the extension URL.init(validatingOpenAPIServerURL:variables:) I realised that the variables could very easily be represented by an enum in the generated code. By doing so it would also provide a compiler checked way to use a non-default variable.

Proposed solution

Server variables that only declare a default value should remain as strings, but if a variable declares the enum property should have a Swift enum generated to represent the values, allowing implementers to know the other possible values and have the compiler guarantee only an allowed value is used; currently this guarantee is at runtime.

Given the same configuration from the motivation, the Servers namespace (enum) would get generated to include enums for the variables.

/// Server URLs defined in the OpenAPI document.
internal enum Servers {
    /// Server URL variables defined in the OpenAPI document.
    internal enum Variables {
        /// The variables for Server1 defined in the OpenAPI document.
        internal enum Server1 {
            /// Server environment.
            ///
            /// The "environment" variable defined in the OpenAPI document. The default value is "prod".
            internal enum Environment: Swift.String {
                case prod
                case staging
                case dev
                /// The default variable.
                internal static var `default`: Environment {
                    return Environment.prod
                }
            }
        }
    }
    /// Example service deployment.
    ///
    /// - Parameters:
    ///   - environment: Server environment.
    ///   - version:
    internal static func server1(
        environment: Variables.Server1.Environment = Variables.Server1.Environment.default,
        version: Swift.String = "v1"
    ) throws -> Foundation.URL {
        try Foundation.URL(
            validatingOpenAPIServerURL: "https://{environment}.example.com/api/{version}",
            variables: [
                .init(
                    name: "environment",
                    value: environment.rawValue
                ),
                .init(
                    name: "version",
                    value: version
                )
            ]
        )
    }
}

Alternatives considered

No response

Additional information

No response

@theoriginalbit theoriginalbit added kind/feature New feature. status/triage Collecting information required to triage the issue. labels Sep 18, 2024
@czechboy0 czechboy0 added status/needs-design Needs further discussion and a concrete proposal. and removed status/triage Collecting information required to triage the issue. labels Sep 18, 2024
@czechboy0 czechboy0 added this to the Post-1.0 milestone Sep 18, 2024
@czechboy0 czechboy0 linked a pull request Oct 4, 2024 that will close this issue
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
kind/feature New feature. status/needs-design Needs further discussion and a concrete proposal.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants